Select binding facts at reads without mixing whole-binding and temporal values. Share conditional activation rules, preserve partial expression order, and bound immutable ancestry work. Memoize temporal results within each query using initializer identity, capture point, budget and dependency proofs; preserve depth limits and source Evidence.
Fixes#3881
* fix(javascript): bound value evaluation through nested closure aliases
A closure that aliases a binding from its enclosing scope evaluates that
binding once live and once at its own capture point. The capture cannot
order a binding declared in another function, so it fell back to a second
live evaluation. Only primitive results were kept, so every level of
nesting doubled the work: 20 nested closures over a non-constant value
took about 14 s, and a 443 KB generated wrapper reached the 300 s
analysis timeout.
Keep a live binding value when no caller could change it: no alias cycle
closes on or above the binding and the expression depth budget was not
reached. Bindings on a cycle are still re-evaluated, so their values and
reasons are unchanged.
Found while building a source-owned reproduction for #1847; that report's
worker heap exhaustion is a separate, already closed defect.
* fix(javascript): keep the expression depth budget for retained values
Reusing a retained composite value from any depth let a chain of wrappers
(s1 = {x: s0}, s2 = {x: s1}, ...) nest past the expression depth budget:
300 wrappers produced a 299-level value where the budget stops at 86, the
serialized IR grew quadratically, and 3,000 wrappers overflowed the stack
in JSON.stringify.
Record the expression depth at which each caller-independent value was
derived and reuse it only at that depth or shallower. A deeper reader
derives the value again and reaches the budget exactly as before. Closure
aliases read their outer binding at one depth on both paths, so nested
closures stay linear.