Skip to content

Commit 6ffd2bb

Browse files
cristianocclaude
andcommitted
Consume the stored variant layout everywhere
Constructor descriptions now carry their declaring variant's layout, minted in datarepr from the declaration, and every consumer reads it instead of re-deriving representation facts: - Matching takes the layout straight from the constructor description; the per-switch type resolution and the sw_layout plumbing are gone, and sw_dispatch is the layout's precomputed dispatch. - Translcore counts payload constructors from the stored layout instead of looking the declaration up in the environment. - Parmatch reads a constructor's untagged block type from the stored layout instead of re-resolving the declaration. With typedecl the only remaining layout computer, the derivation (get_block_type and friends) moves to a new Variant_layout module above Ctype, and the Obj.magic forward references in Ast_untagged_variants are deleted: typing a declaration now determines its representation once, and it is never revisited. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YWw5GW8t4UDEWAzoqcDMkE
1 parent ed3b34d commit 6ffd2bb

10 files changed

Lines changed: 198 additions & 221 deletions

File tree

compiler/ml/ast_untagged_variants.ml

Lines changed: 1 addition & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ type constructor_case = Variant_runtime.constructor_case =
118118
type variant_layout = Variant_runtime.variant_layout = {
119119
constructors: constructor_case array;
120120
constructors_by_name: (int * constructor_case) Map_string.t;
121+
dispatch: Variant_runtime.variant_dispatch;
121122
}
122123
(** Canonical runtime layout in source-constructor order. *)
123124

@@ -132,42 +133,6 @@ type variant_dispatch = Variant_runtime.variant_dispatch = {
132133
(** The whole-variant information needed to choose a JavaScript dispatch
133134
strategy. Constructor identity is carried by each switch arm instead. *)
134135

135-
let dispatch_from_layout layout =
136-
let tag_name = ref None in
137-
let block_types = ref [] in
138-
let literal_tags = ref [] in
139-
let has_null = ref false in
140-
let has_undefined = ref false in
141-
let has_other_literal = ref false in
142-
Array.iter
143-
(function
144-
| Constant {name; tag_type} -> (
145-
let tag =
146-
match tag_type with
147-
| Some tag -> tag
148-
| None -> String name
149-
in
150-
literal_tags := tag :: !literal_tags;
151-
match tag with
152-
| Null -> has_null := true
153-
| Undefined -> has_undefined := true
154-
| String _ | Int _ | Float _ | BigInt _ | Bool _ | Untagged _ ->
155-
has_other_literal := true)
156-
| Block {runtime = {tag_name = constructor_tag_name}; block_type} -> (
157-
if !tag_name = None then tag_name := constructor_tag_name;
158-
match block_type with
159-
| Some block_type -> block_types := block_type :: !block_types
160-
| None -> ()))
161-
layout.constructors;
162-
{
163-
tag_name = !tag_name;
164-
block_types = !block_types;
165-
literal_tags = !literal_tags;
166-
has_null = !has_null;
167-
has_undefined = !has_undefined;
168-
has_other_literal = !has_other_literal;
169-
}
170-
171136
let constructor_by_name layout name =
172137
snd (Map_string.find_exn layout.constructors_by_name name)
173138

@@ -210,16 +175,6 @@ let process_untagged (attrs : Parsetree.attributes) =
210175
| _ -> ());
211176
!st
212177

213-
(* Filled in by [Typedecl] to break the module cycle through [Ctype];
214-
installed at module initialization of the typing layer, so they are set
215-
before any declaration is typed. *)
216-
let extract_concrete_typedecl :
217-
(Env.t -> Types.type_expr -> Path.t * Path.t * Types.type_declaration) ref =
218-
ref (Obj.magic ())
219-
220-
let expand_head : (Env.t -> Types.type_expr -> Types.type_expr) ref =
221-
ref (Obj.magic ())
222-
223178
let process_tag_type (attrs : Parsetree.attributes) =
224179
let st : tag_type option ref = ref None in
225180
Ext_list.iter attrs (fun (({txt; loc}, payload) as attr) ->
@@ -301,57 +256,6 @@ let type_to_instanceof_backed_obj (t : Types.type_expr) =
301256
| _ -> None)
302257
| _ -> None
303258

304-
let get_block_type_from_typ ~env (t : Types.type_expr) : block_type option =
305-
(* First check the original (unexpanded) type for typed arrays and other instance types *)
306-
match type_to_instanceof_backed_obj t with
307-
| Some instance_type -> Some (InstanceType instance_type)
308-
| None -> (
309-
(* If original type didn't match, expand and try standard checks *)
310-
let expanded_t = !expand_head env t in
311-
match expanded_t with
312-
| {desc = Tconstr (path, _, _)} when Path.same path Predef.path_string ->
313-
Some StringType
314-
| {desc = Tconstr (path, _, _)} when Path.same path Predef.path_int ->
315-
Some IntType
316-
| {desc = Tconstr (path, _, _)} when Path.same path Predef.path_float ->
317-
Some FloatType
318-
| {desc = Tconstr (path, _, _)} when Path.same path Predef.path_bigint ->
319-
Some BigintType
320-
| {desc = Tconstr (path, _, _)} when Path.same path Predef.path_bool ->
321-
Some BooleanType
322-
| {desc = Tarrow _} -> Some FunctionType
323-
| {desc = Tconstr _} as expanded_t when type_is_builtin_object expanded_t ->
324-
Some ObjectType
325-
| {desc = Tconstr _} as expanded_t
326-
when type_to_instanceof_backed_obj expanded_t |> Option.is_some -> (
327-
match type_to_instanceof_backed_obj expanded_t with
328-
| None -> None
329-
| Some instance_type -> Some (InstanceType instance_type))
330-
| {desc = Ttuple _} -> Some (InstanceType Array)
331-
| _ -> None)
332-
333-
let get_block_type ~env (cstr : Types.constructor_declaration) :
334-
block_type option =
335-
match (process_untagged cstr.cd_attributes, cstr.cd_args) with
336-
| false, _ -> None
337-
| true, Cstr_tuple [t] when get_block_type_from_typ ~env t |> Option.is_some
338-
->
339-
get_block_type_from_typ ~env t
340-
| true, Cstr_tuple [ty] -> (
341-
let default = Some UnknownType in
342-
match !extract_concrete_typedecl env ty with
343-
| _, _, {type_kind = Type_record (_, Record_unboxed _)} -> default
344-
| _, _, {type_kind = Type_record (_, _)} -> Some ObjectType
345-
| _ -> default
346-
| exception _ -> default)
347-
| true, Cstr_tuple (_ :: _ :: _) ->
348-
(* C(_, _) with at least 2 args is an object *)
349-
Some ObjectType
350-
| true, Cstr_record _ ->
351-
(* inline record is an object *)
352-
Some ObjectType
353-
| true, _ -> None (* TODO: add restrictions here *)
354-
355259
let process_tag_name (attrs : Parsetree.attributes) =
356260
let st = ref None in
357261
Ext_list.iter attrs (fun ({txt; loc}, payload) ->
@@ -485,61 +389,6 @@ let check_invariant ~is_untagged_def ~(consts : (Location.t * tag) list)
485389
let get_cstr_loc_tag (cstr : Types.constructor_declaration) =
486390
(cstr.cd_loc, constructor_tag ~name:(Ident.name cstr.cd_id) cstr.cd_attributes)
487391

488-
let constructor_declaration_from_constructor_description ~env
489-
(cd : Types.constructor_description) : Types.constructor_declaration option
490-
=
491-
match cd.cstr_res.desc with
492-
| Tconstr (path, _, _) -> (
493-
match Env.find_type path env with
494-
| {type_kind = Type_variant (cstrs, _)} ->
495-
Ext_list.find_opt cstrs (fun cstr ->
496-
if cstr.cd_id.name = cd.cstr_name then Some cstr else None)
497-
| _ -> None)
498-
| _ -> None
499-
500-
let layout_from_type_variant ?(is_untagged_def = false) ~env
501-
(cstrs : Types.constructor_declaration list) =
502-
let get_block (cstr : Types.constructor_declaration) : block =
503-
{
504-
runtime = block_runtime ~name:(Ident.name cstr.cd_id) cstr.cd_attributes;
505-
block_type = get_block_type ~env cstr;
506-
}
507-
in
508-
let located_constructors =
509-
List.map
510-
(fun (cstr : Types.constructor_declaration) ->
511-
if is_nullary_variant cstr.cd_args then
512-
let loc, tag = get_cstr_loc_tag cstr in
513-
(loc, Constant tag)
514-
else (cstr.cd_loc, Block (get_block cstr)))
515-
cstrs
516-
in
517-
let consts, blocks =
518-
Ext_list.fold_left located_constructors ([], [])
519-
(fun (consts, blocks) (loc, constructor) ->
520-
match constructor with
521-
| Constant tag -> ((loc, tag) :: consts, blocks)
522-
| Block block -> (consts, (loc, block) :: blocks))
523-
in
524-
check_invariant ~is_untagged_def ~consts ~blocks;
525-
let constructors =
526-
Array.of_list
527-
(List.map (fun (_, constructor) -> constructor) located_constructors)
528-
in
529-
let constructors_by_name =
530-
let _, constructors_by_name =
531-
List.fold_left2
532-
(fun (index, constructors_by_name)
533-
(cstr : Types.constructor_declaration) (_, constructor) ->
534-
( index + 1,
535-
Map_string.add constructors_by_name (Ident.name cstr.cd_id)
536-
(index, constructor) ))
537-
(0, Map_string.empty) cstrs located_constructors
538-
in
539-
constructors_by_name
540-
in
541-
Some {constructors; constructors_by_name}
542-
543392
let check_tag_field_conflicts (cstrs : Types.constructor_declaration list) =
544393
List.iter
545394
(fun (cstr : Types.constructor_declaration) ->
@@ -573,8 +422,6 @@ let check_tag_field_conflicts (cstrs : Types.constructor_declaration list) =
573422

574423
let has_undefined_literal attrs = process_tag_type attrs = Some Undefined
575424

576-
let block_is_object ~env attrs = get_block_type ~env attrs = Some ObjectType
577-
578425
module Dynamic_checks = struct
579426
type op = EqEqEq | NotEqEq | Or | And
580427
type 'a t =

compiler/ml/datarepr.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ let constructor_has_optional_shape
101101
List.exists (fun (x, _) -> x.txt = internal_optional) attrs
102102

103103
let constructor_descrs ty_path decl cstrs =
104+
let layout =
105+
match decl.type_kind with
106+
| Type_variant (_, layout) -> layout
107+
| Type_abstract | Type_record _ | Type_open -> assert false
108+
in
104109
let ty_res = newgenconstr ty_path decl.type_params in
105110
let num_consts = ref 0 and num_nonconsts = ref 0 in
106111
List.iter
@@ -141,6 +146,7 @@ let constructor_descrs ty_path decl cstrs =
141146
cstr_arity = List.length cstr_args;
142147
cstr_identity =
143148
Ordinary_constructor {type_path = ty_path; name = cstr_name};
149+
cstr_layout = Some layout;
144150
cstr_transparent =
145151
!num_consts = 0 && !num_nonconsts = 1 && cstr_args <> []
146152
&& List.exists
@@ -196,6 +202,7 @@ let extension_descr path_ext ext =
196202
cstr_args;
197203
cstr_arity = List.length cstr_args;
198204
cstr_identity = Extension_constructor path_ext;
205+
cstr_layout = None;
199206
cstr_transparent = false;
200207
cstr_private = ext.ext_private;
201208
cstr_generalized = ext.ext_ret_type <> None;

compiler/ml/matching.ml

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,7 +2050,7 @@ let constructor_switch_key layout (cstr : Types.constructor_description) =
20502050
Switch_constructor
20512051
(Ast_untagged_variants.constructor_by_name layout cstr.cstr_name)
20522052

2053-
let combine_constructor sw_layout loc arg ex_pat cstr partial ctx def
2053+
let combine_constructor loc arg ex_pat cstr partial ctx def
20542054
(tag_lambda_list, total1, pats) =
20552055
let is_extension =
20562056
match cstr.cstr_identity with
@@ -2088,7 +2088,7 @@ let combine_constructor sw_layout loc arg ex_pat cstr partial ctx def
20882088
else
20892089
(* Regular concrete type *)
20902090
let layout =
2091-
match sw_layout with
2091+
match cstr.cstr_layout with
20922092
| Some layout -> layout
20932093
| None -> assert false
20942094
in
@@ -2165,9 +2165,7 @@ let combine_constructor sw_layout loc arg ex_pat cstr partial ctx def
21652165
sw_blocks_full = List.length nonconsts >= num_nonconsts;
21662166
sw_blocks = nonconsts;
21672167
sw_failaction = fail_opt;
2168-
sw_dispatch =
2169-
Switch_variant
2170-
(Ast_untagged_variants.dispatch_from_layout layout);
2168+
sw_dispatch = Switch_variant layout.dispatch;
21712169
}
21722170
in
21732171
let hs, sw = share_actions_sw sw in
@@ -2457,24 +2455,6 @@ let arg_to_var arg cls =
24572455
let v = name_pattern "match" cls in
24582456
(v, Lvar v)
24592457

2460-
(* Resolve the canonical variant layout of a constructor pattern's type,
2461-
following manifest chains to the declaration *)
2462-
let layout_from_construct_pattern (pat : pattern) =
2463-
let rec resolve_path (path : Path.t) =
2464-
match Env.find_type path pat.pat_env with
2465-
| {type_kind = Type_variant (cstrs, _)} ->
2466-
Ast_untagged_variants.layout_from_type_variant ~env:pat.pat_env cstrs
2467-
| {type_kind = Type_abstract; type_manifest = Some t} -> (
2468-
match (Ctype.unalias t).desc with
2469-
| Tconstr (pathn, _, _) -> resolve_path pathn
2470-
| _ -> None)
2471-
| {type_kind = Type_abstract; type_manifest = None} -> None
2472-
| {type_kind = Type_record _ | Type_open (* Exceptions *)} -> None
2473-
in
2474-
match (Btype.repr pat.pat_type).desc with
2475-
| Tconstr (path, _, _) -> resolve_path path
2476-
| _ -> assert false
2477-
24782458
(*
24792459
The main compilation function.
24802460
Input:
@@ -2545,11 +2525,10 @@ and do_compile_matching repr partial ctx arg pmh =
25452525
(combine_constant pat.pat_loc arg cst partial)
25462526
ctx pm
25472527
| Tpat_construct (_, cstr, _) ->
2548-
let sw_layout = layout_from_construct_pattern pat in
25492528
compile_test
25502529
(compile_match repr partial)
25512530
partial divide_constructor
2552-
(combine_constructor sw_layout pat.pat_loc arg pat cstr partial)
2531+
(combine_constructor pat.pat_loc arg pat cstr partial)
25532532
ctx pm
25542533
| Tpat_array _ ->
25552534
compile_test

compiler/ml/parmatch.ml

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -560,23 +560,18 @@ let all_record_args lbls =
560560
_,
561561
[({pat_desc = Tpat_construct (_, cd, _)} as pat_construct)] )
562562
when lbl_is_optional () -> (
563-
let cdecl =
564-
Ast_untagged_variants
565-
.constructor_declaration_from_constructor_description
566-
~env:pat.pat_env cd
567-
in
568-
match cdecl with
563+
match cd.cstr_layout with
569564
| None -> x
570-
| Some cstr -> (
565+
| Some layout -> (
571566
match
572-
Ast_untagged_variants.get_block_type ~env:pat.pat_env cstr
567+
Ast_untagged_variants.constructor_by_name layout cd.cstr_name
573568
with
574-
| Some block_type
569+
| Block {block_type = Some block_type}
575570
when not
576571
(Ast_untagged_variants.block_type_can_be_undefined
577572
block_type) ->
578573
(id, lbl, pat_construct, o)
579-
| _ -> x))
574+
| Constant _ | Block _ -> x))
580575
| _ -> x
581576
in
582577
t.(lbl.lbl_pos) <- x)

compiler/ml/translcore.ml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,16 @@ let transl_module =
3636

3737
(* Number of payload-carrying constructors of the variant declaring
3838
[cstr]; part of the runtime representation of its blocks *)
39-
let num_nonconst_constructors env (cstr : Types.constructor_description) =
40-
match cstr.cstr_identity with
41-
| Ordinary_constructor {type_path} -> (
42-
match (Env.find_type type_path env).type_kind with
43-
| Type_variant (cstrs, _) ->
44-
List.length
45-
(List.filter
46-
(fun (cd : Types.constructor_declaration) ->
47-
cd.cd_args <> Cstr_tuple [])
48-
cstrs)
49-
| _ -> assert false)
50-
| Extension_constructor _ -> assert false
39+
let num_nonconst_constructors (cstr : Types.constructor_description) =
40+
match cstr.cstr_layout with
41+
| Some layout ->
42+
Array.fold_left
43+
(fun n (case : Variant_runtime.constructor_case) ->
44+
match case with
45+
| Block _ -> n + 1
46+
| Constant _ -> n)
47+
0 layout.constructors
48+
| None -> assert false
5149

5250
(* Compile an exception/extension definition *)
5351

@@ -812,7 +810,7 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda =
812810
Blk_constructor
813811
{
814812
name = cstr.cstr_name;
815-
num_nonconst = num_nonconst_constructors e.exp_env cstr;
813+
num_nonconst = num_nonconst_constructors cstr;
816814
runtime;
817815
}
818816
in

compiler/ml/typedecl.ml

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ open Primitive
2222
open Types
2323
open Typetexp
2424

25-
let () =
26-
Ast_untagged_variants.extract_concrete_typedecl :=
27-
Ctype.extract_concrete_typedecl
28-
let () = Ast_untagged_variants.expand_head := Ctype.expand_head
29-
3025
type error =
3126
| Repeated_parameter
3227
| Duplicate_constructor of string
@@ -1593,12 +1588,8 @@ let transl_type_decl env rec_flag sdecl_list =
15931588
Ast_untagged_variants.has_untagged decl.type_attributes
15941589
in
15951590
let layout =
1596-
match
1597-
Ast_untagged_variants.layout_from_type_variant ~is_untagged_def
1598-
~env:newenv cstrs
1599-
with
1600-
| Some layout -> layout
1601-
| None -> assert false
1591+
Variant_layout.layout_from_type_variant ~is_untagged_def ~env:newenv
1592+
cstrs
16021593
in
16031594
(id, {decl with type_kind = Type_variant (cstrs, layout)})
16041595
| Type_abstract | Type_record _ | Type_open -> (id, decl))

compiler/ml/types.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ type constructor_description = {
251251
cstr_args: type_expr list; (* Type of the arguments *)
252252
cstr_arity: int; (* Number of arguments *)
253253
cstr_identity: constructor_identity; (* Semantic identity *)
254+
cstr_layout: Variant_runtime.variant_layout option;
255+
(* Runtime layout of the declaring variant; None for extension
256+
constructors *)
254257
cstr_transparent: bool;
255258
(* Sole payload-carrying constructor of an unboxed type: constructing
256259
it is the identity at runtime *)

0 commit comments

Comments
 (0)