原文
…ization
lower_to_ir's default path now consumes the PRE-closure-conversion tree
(post-resolve_scopes): supported local functions emit real `closure` region
ops (params as deferred-region args), and the emitter stops deciding
captures — captured mutable locals get `cell_shared` plans (created at
their K"local" site when one exists, so a loop-local declaration yields a
fresh shared box per iteration), assigned-once/dominating captured locals
stay plain SSA values that in-deferred reads reference by visibility, and
unassigned captured arguments capture their region_arg directly. The shared
promotion fixpoint (promote_capture_cells! included) then decides
value-vs-shared structurally. Scan/planning cover nested method lambdas as
conditional subpaths; frames are entered/exited with their own handler,
break-target, sparam, and return-type scopes; is_ssa desugaring temps (which
scope analysis keeps out of locals_capt) are owned by the frame the scan saw
them in.
Materialization (materialize.jl) turns residual closure regions back into
runtime closures: the capture set IS closure_environment; the type comes
from the existing eval_closure_type machinery (value captures
type-parameterized, surviving shared cells Core.Box or the binding's proven
Base.RefValue{T}); the deferred region is extracted into a standalone
method IR (region 1 = #self# + params, captures via getfield, shared-cell
ops via container field ops, nested closures recursively); the op becomes
apply_type + `new`; and a trampoline method on the new type interprets the
extracted IR, so instances are callable and differentials cross the call
boundary inside UnifiedIR with no aliasing to natively-created types.
Surviving shared cells in the frame lower to the same containers, keeping
use-time UndefVarError with the right variable name through the emitted
guards. promote_capture_cells! learned to accept in-deferred cell_isdefined
guards: a resolved probe proves definedness at the creation site, which
under (a)+(b) equals definedness at call time, so the guards rewrite to
`true` on commit (maybe-undef cells still keep them and the shared
container).
v1 bails (multi-method/kwargs local functions, `where` sparams, varargs,
declared return types on local functions, opaque closures, captured_local,
signatures referencing locals, enclosing-sparam captures) fall back
per-top-level-statement to the eager convert_closures path — loudly, per
the fidelity rule. The whole existing corpus lowers through the region path
(REGION=15/EAGER=0), with new region-corpus differentials (joins, try
joins, counters, typed containers, loop-fresh, multi-shot, recursion via
the Box'd self-capture fallback, nested closures, undef-at-use) and bail
tests asserting the fallback fires.
Co-Authored-By: Claude Fable 5 <[email protected]>