Skip to content

Commit f10b062

Browse files
cristianocclaude
andcommitted
Recognize a jump to an exit without going through make_key
compile_orhandlers asked whether the term it had built was a jump to the exit it was about to wrap a catch around, and asked by calling make_key - which builds a canonical form for comparison - then matching the result and binding the raise's arguments from it. So a fragment of a key reached generated code, and keys are the one place in Lambda built without the constructors: make_key rebuilds raw, so a term it produced was not normalized. The substitution was load-bearing rather than incidental. The term may be [let x = e in exit j x], and it is discarded once recognized, so taking the arguments as written would leave x unbound. make_key happened to substitute alias bindings while canonicalizing, which is what made the arguments safe. as_exit_call does that deliberately: peel alias bindings, substitute them into the arguments, and report the exit. raw_action then has no callers - it was the only consumer of make_key whose result was emitted rather than compared. 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 ef1b4af commit f10b062

1 file changed

Lines changed: 21 additions & 8 deletions

File tree

compiler/ml/matching.ml

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -494,11 +494,6 @@ module Store_exp = Switch.Store (struct
494494
let make_key = Lambda.make_key
495495
end)
496496

497-
let raw_action l =
498-
match make_key l with
499-
| Some l -> l
500-
| None -> l
501-
502497
let tr_raw act =
503498
match make_key act with
504499
| Some act -> act
@@ -2315,20 +2310,38 @@ let compile_list compile_fun division =
23152310
in
23162311
c_rec [] division
23172312

2313+
(* Is [lam] a jump to a static exit, once alias bindings are seen through?
2314+
Those bindings are dropped along with [lam], so they are substituted into
2315+
the raise's arguments rather than left dangling. Recognising this from the
2316+
term itself keeps make_key's output where it belongs - in comparisons. *)
2317+
let as_exit_call lam =
2318+
let rec go env lam =
2319+
match lam with
2320+
| Lstaticraise (i, args) ->
2321+
Some
2322+
( i,
2323+
if env == Ident.empty then args
2324+
else Ext_list.map args (Lambda.subst_lambda env) )
2325+
| Llet (Alias, x, ex, body) ->
2326+
go (Ident.add x (Lambda.subst_lambda env ex) env) body
2327+
| _ -> None
2328+
in
2329+
go Ident.empty lam
2330+
23182331
let compile_orhandlers compile_fun lambda1 total1 ctx to_catch =
23192332
let rec do_rec r total_r = function
23202333
| [] -> (r, total_r)
23212334
| (mat, i, vars, pm) :: rem -> (
23222335
try
23232336
let ctx = select_columns mat ctx in
23242337
let handler_i, total_i = compile_fun ctx pm in
2325-
match raw_action r with
2326-
| Lstaticraise (j, args) ->
2338+
match as_exit_call r with
2339+
| Some (j, args) ->
23272340
if i = j then
23282341
( List.fold_right2 (bind Alias) vars args handler_i,
23292342
jumps_map (ctx_rshift_num (ncols mat)) total_i )
23302343
else do_rec r total_r rem
2331-
| _ ->
2344+
| None ->
23322345
do_rec
23332346
(staticcatch r (i, vars) handler_i)
23342347
(jumps_union (jumps_remove i total_r)

0 commit comments

Comments
 (0)