Skip to content

Commit b60e855

Browse files
Developer playground: compare Lambda before and after optimization (#8636)
* Developer playground: Add lambda views before and after optimisation, including diffs Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com> * Changelog Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com> * Cache playground Lambda diffs and bound token work by block Keep the Lambda view mounted, cache its rendered comparison by input text, and render collapsed context only when expanded. Preserve expansion for unchanged regions across edits. Count shared edges once in the line budget, prioritize atoms in token alignment, and admit whole changed blocks before charging the shared token budget. Cover the algorithm and rendering regressions, and document the API v9 capture boundary. Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com> * Defer hidden Lambda updates and debounce comparisons (#8636) Keep the Before and After dumps unchanged while the Lambda view is hidden. Opening the view reads the latest compiler result. While Diff is open, wait 200 ms after the latest changed result before replacing its comparison; opening Diff remains immediate. Leaving Diff or unmounting cancels its timer. Review: Address cknitt's two non-blocking follow-ups. Regression tests cover hidden panels catching up, consecutive edits, cancellation on tab switches, and expanded context surviving the delayed update. Validation: All 36 developer playground tests, the native compiler suites, the browser compiler bundle tests, production Vite build, OCaml/ReScript/JS format checks, and changelog validation pass after rebasing onto b7c67d2. Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com> * Reuse hidden Lambda panels after compile errors (#8636) Give the cached panel input an identity equality check so repeated errors on the Lambda tab do not notify the unchanged Before and After panels. Review: Address cknitt's final non-blocking follow-up. The regression test reproduces the After panel being rebuilt without this check, verifies reuse across repeated errors, and checks recovery when compilation succeeds. Validation: All 37 developer playground tests, the production Vite build, and the changed files' ReScript/JavaScript format checks pass. Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com> * Publish Lambda panel snapshots only while visible (#8636) Keep the visible panel snapshot in a signal updated by an owned effect. Repeated compile errors leave the signal untouched, so neither hidden panel is invalidated. Showing the Lambda tab publishes the latest input. Why: The locked rescript-signals 3.1.1 still invalidates downstream computeds despite panelInput's equality check. The local install used 3.1.4 and missed this behavior. Reproduced the CI failure with 3.1.1; the existing panel-reuse regression now passes on the locked version. Validation: All 37 playground tests pass with Node 22.23.3 and the locked rescript-signals 3.1.1. The playground compiler build, production Vite build, ReScript formatting, and diff checks pass. Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com> --------- Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
1 parent dc2f6fb commit b60e855

17 files changed

Lines changed: 1263 additions & 18 deletions

‎CONTRIBUTING.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,18 @@ $ node
428428
> eval(result.js_code);
429429
```
430430

431+
### Lambda debug outputs (API v9)
432+
433+
`comp.rescript.compileWithDebug(source)` returns `lambda` before the backend's
434+
Lambda optimization passes and `lambda_optimized` after the whole-term passes,
435+
before export grouping and JavaScript lowering. Both use the same Lambda printer
436+
so their text can be compared directly. JavaScript lowering performs further
437+
transformations; this snapshot is not the final JavaScript IR.
438+
439+
Regular `comp.rescript.compile(source)` does not capture these debug outputs.
440+
Older bundles do not provide `lambda_optimized`; consumers should treat it as
441+
optional when supporting multiple API versions.
442+
431443
### Testing the Playground bundle
432444

433445
Run `yarn workspace playground test` for a quick sanity check to see if all the build artifacts are working together correctly. When releasing the playground bundle, the test will always be executed before publishing to catch regressions.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add before/after optimization views and inline diffs to the developer playground's Lambda tab, with optimized Lambda output in playground API v9, deferred hidden-panel updates, and debounced comparisons while editing. https://github.com/rescript-lang/rescript/pull/8636

‎compiler/core/lam_compile_main.ml‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ let required_modules (lam : Lambda.t) : unit Lam_module_ident.Hash_set.t =
254254
collect lam;
255255
required
256256

257-
let compile (output_prefix : string) export_idents hoisted (lam : Lambda.t) =
257+
let compile ?on_optimized_lambda (output_prefix : string) export_idents hoisted
258+
(lam : Lambda.t) =
258259
let debug_ir = !((Js_config.current ()).debug_ir) in
259260
let diagnostics =
260261
if debug_ir then Some (Ir_diagnostics.create ~output_prefix) else None
@@ -329,6 +330,9 @@ let compile (output_prefix : string) export_idents hoisted (lam : Lambda.t) =
329330
lam
330331
in
331332

333+
(* Capture the final whole-term optimization result before export grouping
334+
and JavaScript lowering. The callback is absent in normal compilation. *)
335+
Option.iter (fun capture -> capture lam) on_optimized_lambda;
332336
let ({Lam_coercion.groups} as coerced_input), meta =
333337
Lam_coercion.coerce_and_group_big_lambda meta lam
334338
in

‎compiler/core/lam_compile_main.mli‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,17 @@
2828
*)
2929

3030
val compile :
31+
?on_optimized_lambda:(Lambda.t -> unit) ->
3132
string ->
3233
Ident.t list ->
3334
Lambda.hoisted_function list ->
3435
Lambda.t ->
3536
J.deps_program
3637
(** For toplevel, [filename] is [""] which is the same as
3738
{!Env.get_unit_name ()}
39+
40+
[on_optimized_lambda], when supplied, observes the whole-term Lambda after
41+
optimization and before export grouping and JavaScript lowering.
3842
*)
3943

4044
val lambda_as_module : J.deps_program -> string -> unit

‎compiler/jsoo/jsoo_playground_main.ml‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@
5353
* v6: Added `config.experimental_features` and `config.jsx_preserve_mode` to the BundleConfig.
5454
* v7: Added debug dump output APIs for developer playground tooling.
5555
* v8: Added genType and source map configuration and compilation outputs.
56+
* v9: Added optimized Lambda output to debug compilation.
5657
* *)
57-
let api_version = "8"
58+
let api_version = "9"
5859

5960
module Js = Js_of_ocaml.Js
6061

@@ -670,8 +671,18 @@ module Compile = struct
670671
let {Translmod.lambda; exports; hoisted_functions} =
671672
Translmod.transl_implementation modulename typed_tree
672673
in
674+
let optimized_lambda = ref None in
675+
let on_optimized_lambda =
676+
if include_debug_outputs then
677+
Some
678+
(fun lambda ->
679+
optimized_lambda :=
680+
Some (Printer.to_string Printlambda.lambda lambda))
681+
else None
682+
in
673683
let lambda_output =
674-
Lam_compile_main.compile "" exports hoisted_functions lambda
684+
Lam_compile_main.compile ?on_optimized_lambda "" exports
685+
hoisted_functions lambda
675686
in
676687
let js_code, source_map =
677688
render_javascript ~module_system ~filename ~source:str ~source_map_mode
@@ -728,7 +739,15 @@ module Compile = struct
728739
("lam", inject @@ Js.string lam);
729740
|]
730741
in
731-
Js.Unsafe.obj (Array.concat [attrs; debug_attrs; gentype_attrs])
742+
let optimized_lambda_attrs =
743+
match !optimized_lambda with
744+
| None -> [||]
745+
| Some output ->
746+
Js.Unsafe.[|("lambda_optimized", inject @@ Js.string output)|]
747+
in
748+
Js.Unsafe.obj
749+
(Array.concat
750+
[attrs; debug_attrs; gentype_attrs; optimized_lambda_attrs])
732751
else Js.Unsafe.obj attrs
733752
with e -> (
734753
match e with

‎packages/dev-playground/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"prepare-pages-site": "node scripts/prepare-pages-site.mjs",
1010
"res:build": "rescript",
1111
"res:watch": "rescript -w",
12-
"test": "rescript && node --test scripts/source-map-navigation.test.mjs scripts/pane-layout.test.mjs",
12+
"test": "rescript && node --test scripts/source-map-navigation.test.mjs scripts/pane-layout.test.mjs scripts/lambda-diff.test.mjs",
1313
"dev": "vite --host 127.0.0.1",
1414
"build": "rescript && vite build",
1515
"preview": "vite preview --host 127.0.0.1"

0 commit comments

Comments
 (0)