You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
hir: class-expression capture snapshot stale for vars assigned after the class — semver Comparator TypeError kills pi-native at init #6604
Next wall of the pi coding-agent bring-up (tracker #6564), directly behind #6593 (PR #6603 makes the bundle compile+link; this bug stops the binary at init).
Symptom
Every pi-native invocation dies during module init:
TypeError: value is not a function
at <anonymous>
Diagnosis (from a --debug-symbols build, breakpoint on js_throw_type_error_not_a_function)
The failing shape is semver's standard CJS layout inside its esbuild __commonJS wrapper:
varComparator=class_Comparator{constructor(comp,options){options=parseOptions(options);// ← throws: parseOptions is undefined
...
}};module.exports=Comparator;varparseOptions=require_parse_options();// assigned AFTER the class definition
Correct JS: the ctor closes over the live parseOptions binding; by the time anything constructs a Comparator (the wrapper has completed), it holds the function.
Perry: the class captures the wrapper-local via the synthesized __perry_cap_<id> machinery. For dynamic construction (js_new_function_construct — subset.js constructs the require_comparator() VALUE), the ctor's capture params are filled from a capture snapshot taken at the class's source position — which predates the var parseOptions = ... assignment, so the snapshot holds undefined forever.
The #6037/#6052 refresh machinery (re-register snapshot after each captured var's assignment + before returns, insert_class_capture_refresh_after_assignments in crates/perry-hir/src/lower_decl/block.rs ~1250) only scans ast::Stmt::Decl(ast::Decl::Class(..)) — class declarations. var C = class _C {...} (a class expression in a var initializer — semver uses this in every class file, and the per-evaluation __perry_ctor_caps value-snapshot path applies) is not covered, so no refresh ever happens for this shape.
Suggested direction
Extend the refresh machinery to the var/let/const <name> = class ... statement shape (both the block-body and lower_fn_expr twins), or refresh the class value's __perry_ctor_caps on assignment to any captured var. Note the naming subtlety: the class registers under its expression ident (_Comparator), not the binding (Comparator), and scope renames must be resolved the same way the decl-path fix does (2026-07-02 audit P0 in block.rs).
Repro: compile secret-tests/pi-target/dist/pi-bundle.mjs with PR #6603's compiler, run HOME=$(mktemp -d) ./pi-native --help.
Activity
fix(hir): extend PerryTS#6037/PerryTS#6052 class-capture refresh to c…
fix(hir): extend PerryTS#6037/PerryTS#6052 class-capture refresh to c…
fix(hir): extend PerryTS#6037/PerryTS#6052 class-capture refresh to c…
fix(hir): extend #6037/#6052 class-capture refresh to class expressio…
runtime: createRequire node:-prefix normalization + diagnostics_chann…
fix(codegen): globalize module-init lets nested in destructure Try sc…