@@ -3952,18 +3952,55 @@ let rec subtype_rec env trace t1 t2 cstrs =
3952
3952
| (Tconstr(p1 , _ , _ ), _ ) when generic_private_abbrev env p1 ->
3953
3953
subtype_rec env trace (expand_abbrev_opt env t1) t2 cstrs
3954
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
3955
+ extract_concrete_typedecl env t1 |> Variant_coercion. can_try_coerce_variant_to_primitive |> Option. is_some
3956
+ ->
3957
+ (* type coercion for variants to primitives *)
3958
+ (match Variant_coercion. can_try_coerce_variant_to_primitive (extract_concrete_typedecl env t1) with
3959
3959
| Some constructors ->
3960
3960
if constructors |> Variant_coercion. can_coerce_variant ~path then
3961
3961
cstrs
3962
3962
else
3963
3963
(trace, t1, t2, ! univar_pairs)::cstrs
3964
3964
| None -> (trace, t1, t2, ! univar_pairs)::cstrs)
3965
- | (Tconstr(_ , [] , _ ), Tconstr(_ , [] , _ )) -> (* type coercion for records *)
3965
+ | (Tconstr(_ , [] , _ ), Tconstr(_ , [] , _ )) -> (* type coercion for variants and records *)
3966
3966
(match extract_concrete_typedecl env t1, extract_concrete_typedecl env t2 with
3967
+ | (_ , _ , {type_kind =Type_variant (c1 ); type_attributes =t1attrs } ), (_ , _ , {type_kind =Type_variant (c2 ); type_attributes =t2attrs } ) ->
3968
+ if
3969
+ Variant_coercion. variant_configuration_can_be_coerced t1attrs t2attrs = false
3970
+ then
3971
+ (trace, t1, t2, ! univar_pairs)::cstrs
3972
+ else
3973
+ let c1_len = List. length c1 in
3974
+ if c1_len > List. length c2 then (trace, t1, t2, ! univar_pairs)::cstrs
3975
+ else
3976
+ let constructor_map = Hashtbl. create c1_len in
3977
+ c2
3978
+ |> List. iter (fun (c : Types.constructor_declaration ) ->
3979
+ Hashtbl. add constructor_map (Ident. name c.cd_id) c);
3980
+ if c1 |> List. for_all (fun (c : Types.constructor_declaration ) ->
3981
+ match (c, Hashtbl. find_opt constructor_map (Ident. name c.cd_id)) with
3982
+ | ( {Types. cd_args = Cstr_record fields1; cd_attributes= c1_attributes},
3983
+ Some {Types. cd_args = Cstr_record fields2; cd_attributes= c2_attributes} ) ->
3984
+ if Variant_coercion. variant_representation_matches c1_attributes c2_attributes then
3985
+ let violation, tl1, tl2 = Record_coercion. check_record_fields fields1 fields2 in
3986
+ if violation then false
3987
+ else
3988
+ begin try
3989
+ let lst = subtype_list env trace tl1 tl2 cstrs in
3990
+ List. length lst = List. length cstrs
3991
+ with | _ -> false end
3992
+ else false
3993
+ | ( {Types. cd_args = Cstr_tuple tl1; cd_attributes= c1_attributes},
3994
+ Some {Types. cd_args = Cstr_tuple tl2; cd_attributes= c2_attributes} ) ->
3995
+ if Variant_coercion. variant_representation_matches c1_attributes c2_attributes then
3996
+ begin try
3997
+ let lst = subtype_list env trace tl1 tl2 cstrs in
3998
+ List. length lst = List. length cstrs
3999
+ with | _ -> false end
4000
+ else false
4001
+ | _ -> false )
4002
+ then cstrs
4003
+ else (trace, t1, t2, ! univar_pairs)::cstrs
3967
4004
| (_ , _ , {type_kind =Type_record (fields1 , repr1 )} ), (_ , _ , {type_kind =Type_record (fields2 , repr2 )} ) ->
3968
4005
let same_repr = match repr1, repr2 with
3969
4006
| (Record_regular | Record_optional_labels _ ), (Record_regular | Record_optional_labels _ ) ->
@@ -3973,30 +4010,8 @@ let rec subtype_rec env trace t1 t2 cstrs =
3973
4010
| Record_extension , Record_extension -> true
3974
4011
| _ -> false in
3975
4012
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
3978
- | _ -> false in
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 *)
3985
- violation := true ;
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
4013
+ let violation, tl1, tl2 = Record_coercion. check_record_fields ~repr1 ~repr2 fields1 fields2 in
4014
+ if violation
4000
4015
then (trace, t1, t2, ! univar_pairs)::cstrs
4001
4016
else
4002
4017
subtype_list env trace tl1 tl2 cstrs
0 commit comments