Skip to content

Commit 8afc614

Browse files
cristianocclaude
andcommitted
Move traversals, static exits and path translation out of Lambda
lambda.ml defined the representation and then a good deal that merely used it. The distinction that matters is whether a function needs to construct terms without going through the constructors: the constructors and the folds they run do, and nothing else does. Everything in the second category can live outside, and saying so in the module structure makes the rule checkable rather than a convention. Lambda_traverse takes the generic walks - shallow_exists, shallow_map_sharing, iter, free_variables, subst_lambda - and make_key, which the preceding commit made expressible through the constructors. Lambda_exits takes the static exit mechanism: the counters, make_exit, as_simple_exit, make_catch_delayed. An exit number and the catch a handler is wrapped in are a protocol over the representation, not part of it. Transl_path takes transl_normal_path and its three callers. This is translation, and it was the only reason lambda.ml depended on Env and Path. Moving the last two out made the type private to them, which found two places building raw because they could rather than because they had to: make_exit's Lstaticraise and transl_normal_path's Lconst, Lglobal_module, Lvar and Lprim. Both now go through the constructors, which for these is the same term. Five helpers that only the folds use - eq_primitive_approx, eq_comparison, const_eq_approx, cmp_int32, cmp_float - stop being exported. lambda.ml goes from 1495 lines to 1200. Generated JavaScript is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8g8qwBARAcvW9MyuKQq8H
1 parent e74111e commit 8afc614

23 files changed

Lines changed: 515 additions & 397 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171

7272
- Normalize Lambda terms where they are built: a match guard stays structured data until its fallthrough is known, and `apply` and `mk_builtin` go through the folding constructors. https://github.com/rescript-lang/rescript/pull/8615
7373
- Replace non-escaping local mutable blocks with scalar bindings when all uses are direct field accesses, generalizing reference unboxing to multi-field records and references captured by JavaScript closures. https://github.com/rescript-lang/rescript/pull/8617
74+
- Split `lambda.ml` into the IR and its traversals, static exits and path translation, so the module defining `Lambda.t` no longer reaches into `Env` or `Path`. https://github.com/rescript-lang/rescript/pull/8618
7475
- Merge the duplicate Lam intermediate representation into Lambda, removing the conversion layer and obsolete supporting infrastructure. Lambda is now a single private, normalized representation, with generated JavaScript remaining semantically unchanged. https://github.com/rescript-lang/rescript/pull/8608
7576
- Add genType and source map controls and output to the developer playground. https://github.com/rescript-lang/rescript/pull/8448
7677
- Rework the object-type representation end to end: object rows are plain field chains carrying a per-field mutability state (no phantom setter members), object literals are typed directly and property access and assignment are first-class AST and Lambda nodes shared between the Lambda and JS pipelines, and dead class-system remnants (the field-presence lattice, the class-abbreviation memo on object types, method-send typing) are removed. https://github.com/rescript-lang/rescript/pull/8597

compiler/core/lam_compile.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ let compile output_prefix =
12831283
(lambda_cxt : Lam_compile_context.t) =
12841284
let new_cxt = {lambda_cxt with continuation = NeedValue Not_tail} in
12851285
let emitted_id =
1286-
if Set_ident.mem (Lambda.free_variables body) id then id
1286+
if Set_ident.mem (Lambda_traverse.free_variables body) id then id
12871287
else Ext_ident.create_tmp ~name:"_for_of" ()
12881288
in
12891289
let block =
@@ -1306,7 +1306,7 @@ let compile output_prefix =
13061306
(body : Lambda.t) (lambda_cxt : Lam_compile_context.t) =
13071307
let new_cxt = {lambda_cxt with continuation = NeedValue Not_tail} in
13081308
let emitted_id =
1309-
if Set_ident.mem (Lambda.free_variables body) id then id
1309+
if Set_ident.mem (Lambda_traverse.free_variables body) id then id
13101310
else Ext_ident.create_tmp ~name:"_for_await_of" ()
13111311
in
13121312
let block =

compiler/core/lam_compile_main.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ let required_modules (lam : Lambda.t) : Lam_module_ident.Hash_set.t =
255255
| Lglobal_module id ->
256256
Lam_module_ident.Hash_set.add required (Lam_module_ident.of_ml id)
257257
| _ -> ());
258-
Lambda.iter collect lam
258+
Lambda_traverse.iter collect lam
259259
in
260260
collect lam;
261261
required

compiler/core/lam_dce.ml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,23 @@ let remove export_idents (rest : Lam_group.t list) : Lam_group.t list =
4646
Ext_list.fold_left rest export_idents (fun acc x ->
4747
match x with
4848
| Single (kind, id, lam) -> (
49-
Hash_ident.add ident_free_vars id (Lambda.free_variables lam);
49+
Hash_ident.add ident_free_vars id (Lambda_traverse.free_variables lam);
5050
match kind with
5151
| Alias | StrictOpt -> acc
5252
| Strict | Variable -> id :: acc)
5353
| Recursive bindings ->
5454
Ext_list.fold_left bindings acc (fun acc (id, lam) ->
55-
Hash_ident.add ident_free_vars id (Lambda.free_variables lam);
55+
Hash_ident.add ident_free_vars id
56+
(Lambda_traverse.free_variables lam);
5657
match lam with
5758
| Lfunction _ -> acc
5859
| _ -> id :: acc)
5960
| Nop lam ->
6061
if Lam_analysis.no_side_effects lam then acc
6162
else
6263
(* its free varaibles here will be defined above *)
63-
Set_ident.fold (Lambda.free_variables lam) acc (fun x acc ->
64-
x :: acc))
64+
Set_ident.fold (Lambda_traverse.free_variables lam) acc
65+
(fun x acc -> x :: acc))
6566
in
6667
let visited = transitive_closure initial_idents ident_free_vars in
6768
Ext_list.fold_left rest [] (fun acc x ->

compiler/core/lam_exit_code.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ let has_exit_code lam exits =
2828
| Lfunction _ -> false
2929
(* static exit can not cross function boundary *)
3030
| Lstaticraise (p, _) when exits p -> true
31-
| _ -> Lambda.shallow_exists aux lam
31+
| _ -> Lambda_traverse.shallow_exists aux lam
3232
in
3333
aux lam
3434

3535
let rec has_exit (lam : Lambda.t) =
3636
match lam with
3737
| Lfunction _ -> false
3838
| Lstaticraise (_, _) -> true
39-
| _ -> Lambda.shallow_exists has_exit lam
39+
| _ -> Lambda_traverse.shallow_exists has_exit lam

compiler/core/lam_pass_exits.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ let subst_helper (subst : subst_tbl) (query : int -> int) (lam : Lambda.t) :
197197
Ext_list.fold_right2 xs ys Ident.empty (fun x y t ->
198198
Ident.add x (Lambda.var y) t)
199199
in
200-
Ext_list.fold_right2 ys ls (Lambda.subst_lambda env handler)
200+
Ext_list.fold_right2 ys ls (Lambda_traverse.subst_lambda env handler)
201201
(fun y l r -> Lambda.let_ Strict y l r)
202202
| None -> Lambda.staticraise i ls)
203203
| Lvar _ | Lconst _ -> lam

compiler/core/lam_pass_guard_raises.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ let rec guard_raises (lam : Lambda.t) : Lambda.t =
33
| Lifthenelse (a, (Lprim {primitive = Praise} as b), c) -> (
44
match c with
55
(* A constant alternative is already as flat as it gets. *)
6-
| Lconst _ -> Lambda.shallow_map_sharing guard_raises lam
6+
| Lconst _ -> Lambda_traverse.shallow_map_sharing guard_raises lam
77
| _ ->
88
Lambda.seq
99
(Lambda.if_ (guard_raises a) b Lambda.lambda_unit)
1010
(guard_raises c))
11-
| _ -> Lambda.shallow_map_sharing guard_raises lam
11+
| _ -> Lambda_traverse.shallow_map_sharing guard_raises lam

compiler/core/lam_pass_sroa.ml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ let rec analyze block uses (lam : Lambda.t) =
4747
else false
4848
| _ ->
4949
not
50-
(Lambda.shallow_exists (fun child -> not (analyze block uses child)) lam)
50+
(Lambda_traverse.shallow_exists
51+
(fun child -> not (analyze block uses child))
52+
lam)
5153

5254
let discard_value value body =
5355
if Lam_analysis.no_side_effects value then body else Lambda.seq value body
@@ -68,7 +70,7 @@ let rec rewrite block fields uses (lam : Lambda.t) =
6870
loudly instead of silently losing the write. *)
6971
| Lvar id when Ident.same id block -> assert false
7072
| Lassign (id, _) when Ident.same id block -> assert false
71-
| _ -> Lambda.shallow_map_sharing (rewrite block fields uses) lam
73+
| _ -> Lambda_traverse.shallow_map_sharing (rewrite block fields uses) lam
7274

7375
let fields_for_block block info field_count =
7476
let fallback () =
@@ -141,4 +143,4 @@ let rec simplify (lam : Lambda.t) =
141143
| _ ->
142144
if init' == init && body' == body then lam
143145
else Lambda.let_ kind block init' body')
144-
| _ -> Lambda.shallow_map_sharing simplify lam
146+
| _ -> Lambda_traverse.shallow_map_sharing simplify lam

compiler/core/polyvar_pattern_match.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ let convert (xs : input) : output =
4545
let os : value list ref = ref [] in
4646
xs
4747
|> List.iteri (fun i (hash, (name, act)) ->
48-
match Lambda.make_key act with
48+
match Lambda_traverse.make_key act with
4949
| None -> os := {stamp = i; hash_names_act = ([(hash, name)], act)} :: !os
5050
| Some key ->
5151
Coll.add_or_update coll key

0 commit comments

Comments
 (0)