Skip to content

Commit 3eb7b49

Browse files
committed
restructure guard for variant coercion
1 parent 02b4281 commit 3eb7b49

File tree

2 files changed

+59
-52
lines changed

2 files changed

+59
-52
lines changed

jscomp/ml/ctype.ml

+47-44
Original file line numberDiff line numberDiff line change
@@ -3951,56 +3951,59 @@ let rec subtype_rec env trace t1 t2 cstrs =
39513951
end
39523952
| (Tconstr(p1, _, _), _) when generic_private_abbrev env p1 ->
39533953
subtype_rec env trace (expand_abbrev_opt env t1) t2 cstrs
3954-
| (Tconstr(_, [], _), Tconstr(path, [], _)) -> (* type coercion for variants and records *)
3955-
(match extract_concrete_typedecl env t1 with
3956-
| (_, _, {type_kind=Type_variant constructors}) ->
3957-
if Variant_coercion.can_coerce_variant constructors ~path then
3958-
cstrs
3954+
| (Tconstr(_, [], _), Tconstr(path, [], _)) when Variant_coercion.can_coerce_path path &&
3955+
extract_concrete_typedecl env t1 |> Variant_coercion.is_variant_typedecl |> Option.is_some
3956+
->
3957+
(* type coercion for variants *)
3958+
(match Variant_coercion.is_variant_typedecl (extract_concrete_typedecl env t1) with
3959+
| Some constructors ->
3960+
if constructors |> Variant_coercion.can_coerce_variant ~path then
3961+
cstrs
39593962
else
39603963
(trace, t1, t2, !univar_pairs)::cstrs
3961-
| (_, _, {type_kind=Type_record (fields1, repr1)}) -> (
3962-
match extract_concrete_typedecl env t2 with
3963-
| (_, _, {type_kind=Type_record (fields2, repr2)}) ->
3964-
let same_repr = match repr1, repr2 with
3965-
| (Record_regular | Record_optional_labels _), (Record_regular | Record_optional_labels _) ->
3966-
true (* handled in the fields checks *)
3967-
| Record_unboxed b1, Record_unboxed b2 -> b1 = b2
3968-
| Record_inlined _, Record_inlined _ -> repr1 = repr2
3969-
| Record_extension, Record_extension -> true
3964+
| None -> (trace, t1, t2, !univar_pairs)::cstrs)
3965+
| (Tconstr(_, [], _), Tconstr(_, [], _)) -> (* type coercion for records *)
3966+
(match extract_concrete_typedecl env t1, extract_concrete_typedecl env t2 with
3967+
| (_, _, {type_kind=Type_record (fields1, repr1)}), (_, _, {type_kind=Type_record (fields2, repr2)}) ->
3968+
let same_repr = match repr1, repr2 with
3969+
| (Record_regular | Record_optional_labels _), (Record_regular | Record_optional_labels _) ->
3970+
true (* handled in the fields checks *)
3971+
| Record_unboxed b1, Record_unboxed b2 -> b1 = b2
3972+
| Record_inlined _, Record_inlined _ -> repr1 = repr2
3973+
| Record_extension, Record_extension -> true
3974+
| _ -> false in
3975+
if same_repr then
3976+
let field_is_optional id repr = match repr with
3977+
| Record_optional_labels lbls -> List.mem (Ident.name id) lbls
39703978
| _ -> false in
3971-
if same_repr then
3972-
let field_is_optional id repr = match repr with
3973-
| Record_optional_labels lbls -> List.mem (Ident.name id) lbls
3974-
| _ -> false in
3975-
let violation = ref false in
3976-
let label_decl_sub (acc1, acc2) ld2 =
3977-
match Ext_list.find_first fields1 (fun ld1 -> ld1.ld_id.name = ld2.ld_id.name) with
3978-
| Some ld1 ->
3979-
if field_is_optional ld1.ld_id repr1 <> (field_is_optional ld2.ld_id repr2) then
3980-
(* optional field can't be modified *)
3981-
violation := true;
3982-
let get_as (({txt}, payload) : Parsetree.attribute) =
3983-
if txt = "as" then Ast_payload.is_single_string payload
3984-
else None in
3985-
let get_as_name ld = match Ext_list.filter_map ld.ld_attributes get_as with
3986-
| [] -> ld.ld_id.name
3987-
| (s,_)::_ -> s in
3988-
if get_as_name ld1 <> get_as_name ld2 then violation := true;
3989-
ld1.ld_type :: acc1, ld2.ld_type :: acc2
3990-
| None ->
3991-
(* field must be present *)
3979+
let violation = ref false in
3980+
let label_decl_sub (acc1, acc2) ld2 =
3981+
match Ext_list.find_first fields1 (fun ld1 -> ld1.ld_id.name = ld2.ld_id.name) with
3982+
| Some ld1 ->
3983+
if field_is_optional ld1.ld_id repr1 <> (field_is_optional ld2.ld_id repr2) then
3984+
(* optional field can't be modified *)
39923985
violation := true;
3993-
(acc1, acc2) in
3994-
let tl1, tl2 = List.fold_left label_decl_sub ([], []) fields2 in
3995-
if !violation
3996-
then (trace, t1, t2, !univar_pairs)::cstrs
3997-
else
3998-
subtype_list env trace tl1 tl2 cstrs
3986+
let get_as (({txt}, payload) : Parsetree.attribute) =
3987+
if txt = "as" then Ast_payload.is_single_string payload
3988+
else None in
3989+
let get_as_name ld = match Ext_list.filter_map ld.ld_attributes get_as with
3990+
| [] -> ld.ld_id.name
3991+
| (s,_)::_ -> s in
3992+
if get_as_name ld1 <> get_as_name ld2 then violation := true;
3993+
ld1.ld_type :: acc1, ld2.ld_type :: acc2
3994+
| None ->
3995+
(* field must be present *)
3996+
violation := true;
3997+
(acc1, acc2) in
3998+
let tl1, tl2 = List.fold_left label_decl_sub ([], []) fields2 in
3999+
if !violation
4000+
then (trace, t1, t2, !univar_pairs)::cstrs
39994001
else
4000-
(trace, t1, t2, !univar_pairs)::cstrs
4001-
| _ -> (trace, t1, t2, !univar_pairs)::cstrs
4002-
| exception Not_found -> (trace, t1, t2, !univar_pairs)::cstrs)
4002+
subtype_list env trace tl1 tl2 cstrs
4003+
else
4004+
(trace, t1, t2, !univar_pairs)::cstrs
40034005
| _ -> (trace, t1, t2, !univar_pairs)::cstrs
4006+
| exception Not_found -> (trace, t1, t2, !univar_pairs)::cstrs
40044007
)
40054008
(* | (_, Tconstr(p2, _, _)) when generic_private_abbrev false env p2 ->
40064009
subtype_rec env trace t1 (expand_abbrev_opt env t2) cstrs *)

jscomp/ml/variant_coercion.ml

+12-8
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,16 @@ let can_coerce_path (path : Path.t) =
4545

4646
let can_coerce_variant ~(path : Path.t)
4747
(constructors : Types.constructor_declaration list) =
48-
if can_coerce_path path then
49-
if Path.same path Predef.path_string && can_coerce_to_string constructors
50-
then true
51-
else if Path.same path Predef.path_int && can_coerce_to_int constructors
52-
then true
53-
else if Path.same path Predef.path_float && can_coerce_to_float constructors
54-
then true
55-
else false
48+
if Path.same path Predef.path_string && can_coerce_to_string constructors then
49+
true
50+
else if Path.same path Predef.path_int && can_coerce_to_int constructors then
51+
true
52+
else if Path.same path Predef.path_float && can_coerce_to_float constructors
53+
then true
5654
else false
55+
56+
let is_variant_typedecl
57+
((_, _, typedecl) : Path.t * Path.t * Types.type_declaration) =
58+
match typedecl with
59+
| {type_kind = Type_variant constructors} -> Some constructors
60+
| _ -> None

0 commit comments

Comments
 (0)