Skip to content

Commit 91f1c2c

Browse files
flambda-backend: Refactor check_representable in typedecl.ml (#2656)
* Move `check_representable` * Call `check_representable` earlier * Fix * Temp promote test * Push through `unboxed` * Remove redundant checks * Comments and formatting * Small fixes --------- Co-authored-by: Diana Kalinichenko <[email protected]>
1 parent 4d41b55 commit 91f1c2c

File tree

2 files changed

+76
-77
lines changed

2 files changed

+76
-77
lines changed

testsuite/tests/typing-layouts/basics.ml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -605,14 +605,7 @@ Error: Layout void is more experimental than allowed by the enabled layouts exte
605605

606606
type ('a : any) any4 = Any4 of 'a
607607
[%%expect{|
608-
Line 1, characters 23-33:
609-
1 | type ('a : any) any4 = Any4 of 'a
610-
^^^^^^^^^^
611-
Error: Constructor argument types must have a representable layout.
612-
The layout of 'a is any, because
613-
of the annotation on 'a in the declaration of the type any4.
614-
But the layout of 'a must be representable, because
615-
it's the type of a constructor field.
608+
type 'a any4 = Any4 of 'a
616609
|}];;
617610

618611
(************************************************************)

typing/typedecl.ml

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,34 @@ let set_private_row env loc p decl =
381381
in
382382
set_type_desc rv (Tconstr (p, decl.type_params, ref Mnil))
383383

384-
let transl_labels ~new_var_jkind env univars closed lbls =
384+
(* Makes sure a type is representable. When called with a type variable, will
385+
lower [any] to a sort variable if [allow_unboxed = true], and to [value]
386+
if [allow_unboxed = false]. *)
387+
(* CR layouts: Many places where [check_representable] is called in this file
388+
should be replaced with checks at the places where values of those types are
389+
constructed. We've been conservative here in the first version. This is the
390+
same issue as with arrows. *)
391+
let check_representable ~why ~allow_unboxed env loc kloc typ =
392+
match Ctype.type_sort ~why env typ with
393+
(* CR layouts v5: This is a convenient place to rule out non-value types in
394+
structures that don't support them yet. (A callsite passes
395+
[~allow_unboxed:true] to indicate that non-value types are allowed.)
396+
When we support mixed blocks everywhere, this [check_representable]
397+
will have outlived its usefulness and we can delete it.
398+
*)
399+
(* CR layouts v2.5: This rules out non-value types in [@@unboxed] types. No
400+
real need to rule that out - I just haven't had time to write tests for it
401+
yet. *)
402+
| Ok s -> begin
403+
if not allow_unboxed then
404+
match Jkind.Sort.get_default_value s with
405+
| Void | Value -> ()
406+
| Float64 | Float32 | Word | Bits32 | Bits64 as const ->
407+
raise (Error (loc, Invalid_jkind_in_block (typ, const, kloc)))
408+
end
409+
| Error err -> raise (Error (loc,Jkind_sort {kloc; typ; err}))
410+
411+
let transl_labels ~new_var_jkind ~allow_unboxed env univars closed lbls kloc =
385412
assert (lbls <> []);
386413
let all_labels = ref String.Set.empty in
387414
List.iter
@@ -421,6 +448,8 @@ let transl_labels ~new_var_jkind env univars closed lbls =
421448
(fun ld ->
422449
let ty = ld.ld_type.ctyp_type in
423450
let ty = match get_desc ty with Tpoly(t,[]) -> t | _ -> ty in
451+
check_representable ~why:(Label_declaration ld.ld_id)
452+
~allow_unboxed env ld.ld_loc kloc ty;
424453
{Types.ld_id = ld.ld_id;
425454
ld_mutable = ld.ld_mutable;
426455
ld_global = ld.ld_global;
@@ -435,24 +464,42 @@ let transl_labels ~new_var_jkind env univars closed lbls =
435464
lbls in
436465
lbls, lbls'
437466

438-
let transl_types_gf ~new_var_jkind env univars closed tyl =
467+
let transl_types_gf ~new_var_jkind ~allow_unboxed
468+
env loc univars closed tyl kloc =
439469
let mk arg =
440470
let cty = transl_simple_type ~new_var_jkind env ?univars ~closed Mode.Alloc.Const.legacy arg in
441471
let gf = Typemode.transl_global_flags
442472
(Jane_syntax.Mode_expr.of_attrs arg.ptyp_attributes |> fst) in
443473
(cty, gf)
444474
in
445475
let tyl_gfl = List.map mk tyl in
446-
let tyl_gfl' = List.map (fun (cty, gf) -> cty.ctyp_type, gf) tyl_gfl in
476+
let tyl_gfl' = List.mapi (fun idx (cty, gf) ->
477+
check_representable ~why:(Constructor_declaration idx) ~allow_unboxed
478+
env loc kloc cty.ctyp_type;
479+
cty.ctyp_type, gf) tyl_gfl
480+
in
447481
tyl_gfl, tyl_gfl'
448482

449-
let transl_constructor_arguments ~new_var_jkind env univars closed = function
483+
let transl_constructor_arguments ~new_var_jkind ~unboxed
484+
env loc univars closed = function
450485
| Pcstr_tuple l ->
451-
let flds, flds' = transl_types_gf ~new_var_jkind env univars closed l in
452-
Types.Cstr_tuple flds',
453-
Cstr_tuple flds
486+
let flds, flds' =
487+
(* CR layouts: we forbid [@@unboxed] variants from being
488+
non-value, see comment in [check_representable]. *)
489+
transl_types_gf ~new_var_jkind ~allow_unboxed:(not unboxed)
490+
env loc univars closed l (Cstr_tuple { unboxed })
491+
in
492+
Types.Cstr_tuple flds', Cstr_tuple flds
454493
| Pcstr_record l ->
455-
let lbls, lbls' = transl_labels ~new_var_jkind env univars closed l in
494+
let lbls, lbls' =
495+
(* CR layouts: we forbid fields of inlined records from being
496+
non-value, see comment in [check_representable].
497+
When we allow mixed inline records, we still want to
498+
disallow non-value types in unboxed records, so this
499+
should become `not unboxed`, as in the `Pcstr_tuple` case. *)
500+
transl_labels ~new_var_jkind ~allow_unboxed:false
501+
env univars closed l (Inlined_record { unboxed })
502+
in
456503
Types.Cstr_record lbls',
457504
Cstr_record lbls
458505

@@ -462,7 +509,7 @@ let transl_constructor_arguments ~new_var_jkind env univars closed = function
462509
defined types. It is updated later by [update_constructor_arguments_jkinds]
463510
*)
464511
let make_constructor
465-
env loc ~cstr_path ~type_path type_params (svars : _ Either.t)
512+
env loc ~cstr_path ~type_path ~unboxed type_params (svars : _ Either.t)
466513
sargs sret_type =
467514
let tvars = match svars with
468515
| Left vars_only -> List.map (fun v -> v.txt, None) vars_only
@@ -484,7 +531,8 @@ let make_constructor
484531
match sret_type with
485532
| None ->
486533
let args, targs =
487-
transl_constructor_arguments ~new_var_jkind:Any env None true sargs
534+
transl_constructor_arguments ~new_var_jkind:Any ~unboxed
535+
env loc None true sargs
488536
in
489537
tvars, targs, None, args, None
490538
| Some sret_type ->
@@ -510,7 +558,8 @@ let make_constructor
510558
in
511559
let univars = if closed then Some univar_list else None in
512560
let args, targs =
513-
transl_constructor_arguments ~new_var_jkind:Sort env univars closed sargs
561+
transl_constructor_arguments ~new_var_jkind:Sort ~unboxed
562+
env loc univars closed sargs
514563
in
515564
let tret_type =
516565
transl_simple_type ~new_var_jkind:Sort env ?univars ~closed Mode.Alloc.Const.legacy
@@ -759,7 +808,7 @@ let transl_declaration env sdecl (id, uid) =
759808
attributes
760809
in
761810
let tvars, targs, tret_type, args, ret_type =
762-
make_constructor env scstr.pcd_loc
811+
make_constructor ~unboxed:unbox env scstr.pcd_loc
763812
~cstr_path:(Path.Pident name) ~type_path:path params
764813
svars scstr.pcd_args scstr.pcd_res
765814
in
@@ -813,7 +862,12 @@ let transl_declaration env sdecl (id, uid) =
813862
in
814863
Ttype_variant tcstrs, Type_variant (cstrs, rep), jkind
815864
| Ptype_record lbls ->
816-
let lbls, lbls' = transl_labels ~new_var_jkind:Any env None true lbls in
865+
let lbls, lbls' =
866+
(* CR layouts: we forbid [@@unboxed] records from being
867+
non-value, see comment in [check_representable]. *)
868+
transl_labels ~new_var_jkind:Any ~allow_unboxed:(not unbox)
869+
env None true lbls (Record { unboxed = unbox })
870+
in
817871
let rep, jkind =
818872
(* Note this is inaccurate, using `Record_boxed` in cases where the
819873
correct representation is [Record_float], [Record_ufloat], or
@@ -1089,45 +1143,13 @@ let check_coherence env loc dpath decl =
10891143
let check_abbrev env sdecl (id, decl) =
10901144
(id, check_coherence env sdecl.ptype_loc (Path.Pident id) decl)
10911145

1092-
(* Makes sure a type is representable. Will lower "any" to "value". *)
1093-
(* CR layouts: In the places where this is used, we first call this to
1094-
ensure a type is representable, and then call [Ctype.type_jkind] to get the
1095-
most precise jkind. These could be combined into some new function
1096-
[Ctype.type_jkind_representable] that avoids duplicated work *)
1097-
(* CR layouts: Many places where [check_representable] is called in this file
1098-
should be replaced with checks at the places where values of those types are
1099-
constructed. We've been conservative here in the first version. This is the
1100-
same issue as with arrows. *)
1101-
let check_representable ~why ~allow_unboxed env loc kloc typ =
1102-
match Ctype.type_sort ~why env typ with
1103-
(* CR layouts v3: This is a convenient place to rule out non-value types in
1104-
structures that don't support them yet. (A callsite passes
1105-
[~allow_unboxed:true] to indicate that non-value types are allowed.)
1106-
When we support mixed blocks everywhere, this [check_representable]
1107-
will have outlived its usefulness and we can delete it.
1108-
*)
1109-
(* CR layouts v2.5: This rules out non-value types in [@@unboxed] types. No
1110-
real need to rule that out - I just haven't had time to write tests for it
1111-
yet. *)
1112-
| Ok s -> begin
1113-
match Jkind.Sort.get_default_value s with
1114-
(* All calls to this are part of [update_decl_jkind], which happens after
1115-
all the defaulting, so we don't expect this actually defaults the
1116-
sort - we just want the [const]. *)
1117-
| Void | Value -> ()
1118-
| Float64 | Float32 | Word | Bits32 | Bits64 as const ->
1119-
if not allow_unboxed then
1120-
raise (Error (loc, Invalid_jkind_in_block (typ, const, kloc)))
1121-
end
1122-
| Error err -> raise (Error (loc,Jkind_sort {kloc; typ; err}))
1123-
11241146
(* The [update_x_jkinds] functions infer more precise jkinds in the type kind,
11251147
including which fields of a record are void. This would be hard to do during
11261148
[transl_declaration] due to mutually recursive types.
11271149
*)
11281150
(* [update_label_jkinds] additionally returns whether all the jkinds
11291151
were void *)
1130-
let update_label_jkinds env loc lbls named ~is_inlined =
1152+
let update_label_jkinds env loc lbls named =
11311153
(* [named] is [Some jkinds] for top-level records (we will update the
11321154
jkinds) and [None] for inlined records. *)
11331155
(* CR layouts v5: it wouldn't be too hard to support records that are all
@@ -1137,15 +1159,8 @@ let update_label_jkinds env loc lbls named ~is_inlined =
11371159
| None -> fun _ _ -> ()
11381160
| Some jkinds -> fun idx jkind -> jkinds.(idx) <- jkind
11391161
in
1140-
let kloc =
1141-
if is_inlined
1142-
then Inlined_record { unboxed = false }
1143-
else Record { unboxed = false }
1144-
in
11451162
let lbls =
1146-
List.mapi (fun idx (Types.{ld_type; ld_id; ld_loc} as lbl) ->
1147-
check_representable ~why:(Label_declaration ld_id)
1148-
~allow_unboxed:(Option.is_some named) env ld_loc kloc ld_type;
1163+
List.mapi (fun idx (Types.{ld_type} as lbl) ->
11491164
let ld_jkind = Ctype.type_jkind env ld_type in
11501165
update idx ld_jkind;
11511166
{lbl with ld_jkind}
@@ -1163,13 +1178,11 @@ let update_constructor_arguments_jkinds env loc cd_args jkinds =
11631178
match cd_args with
11641179
| Types.Cstr_tuple tys ->
11651180
List.iteri (fun idx (ty,_) ->
1166-
check_representable ~why:(Constructor_declaration idx) ~allow_unboxed:true
1167-
env loc (Cstr_tuple { unboxed = false }) ty;
11681181
jkinds.(idx) <- Ctype.type_jkind env ty) tys;
11691182
cd_args, Array.for_all Jkind.is_void_defaulting jkinds
11701183
| Types.Cstr_record lbls ->
11711184
let lbls, all_void =
1172-
update_label_jkinds env loc lbls None ~is_inlined:true
1185+
update_label_jkinds env loc lbls None
11731186
in
11741187
jkinds.(0) <- Jkind.value ~why:Boxed_record;
11751188
Types.Cstr_record lbls, all_void
@@ -1401,14 +1414,12 @@ let update_decl_jkind env dpath decl =
14011414
(* returns updated labels, updated rep, and updated jkind *)
14021415
let update_record_kind loc lbls rep =
14031416
match lbls, rep with
1404-
| [Types.{ld_type; ld_id; ld_loc} as lbl], Record_unboxed ->
1405-
check_representable ~why:(Label_declaration ld_id) ~allow_unboxed:false
1406-
env ld_loc (Record { unboxed = true }) ld_type;
1417+
| [Types.{ld_type} as lbl], Record_unboxed ->
14071418
let ld_jkind = Ctype.type_jkind env ld_type in
14081419
[{lbl with ld_jkind}], Record_unboxed, ld_jkind
14091420
| _, Record_boxed jkinds ->
14101421
let lbls, all_void =
1411-
update_label_jkinds env loc lbls (Some jkinds) ~is_inlined:false
1422+
update_label_jkinds env loc lbls (Some jkinds)
14121423
in
14131424
let jkind = Jkind.for_boxed_record ~all_void in
14141425
let reprs =
@@ -1515,18 +1526,13 @@ let update_decl_jkind env dpath decl =
15151526
let update_variant_kind cstrs rep =
15161527
(* CR layouts: factor out duplication *)
15171528
match cstrs, rep with
1518-
| [{Types.cd_args;cd_loc} as cstr], Variant_unboxed -> begin
1529+
| [{Types.cd_args} as cstr], Variant_unboxed -> begin
15191530
match cd_args with
15201531
| Cstr_tuple [ty,_] -> begin
1521-
check_representable ~why:(Constructor_declaration 0)
1522-
~allow_unboxed:false env cd_loc (Cstr_tuple { unboxed = true }) ty;
15231532
let jkind = Ctype.type_jkind env ty in
15241533
cstrs, Variant_unboxed, jkind
15251534
end
1526-
| Cstr_record [{ld_type; ld_id; ld_loc} as lbl] -> begin
1527-
check_representable ~why:(Label_declaration ld_id)
1528-
~allow_unboxed:false env ld_loc (Inlined_record { unboxed = true })
1529-
ld_type;
1535+
| Cstr_record [{ld_type} as lbl] -> begin
15301536
let ld_jkind = Ctype.type_jkind env ld_type in
15311537
[{ cstr with Types.cd_args =
15321538
Cstr_record [{ lbl with ld_jkind }] }],
@@ -2217,7 +2223,7 @@ let transl_extension_constructor_decl
22172223
env type_path typext_params loc id svars sargs sret_type =
22182224
let tvars, targs, tret_type, args, ret_type =
22192225
make_constructor env loc
2220-
~cstr_path:(Pident id) ~type_path typext_params
2226+
~cstr_path:(Pident id) ~type_path ~unboxed:false typext_params
22212227
svars sargs sret_type
22222228
in
22232229
let num_args =

0 commit comments

Comments
 (0)