Symptom
After #460 (contextual-keyword re-exports) lands, the link of the Effect repro from #321 still fails on ~7 missing symbols that don't fit the keyword pattern. Filing as a single investigation bucket since they likely share root causes (mangling / class-vs-function emission) and are easier to triage together than as 7 micro-issues.
Missing symbols (post-#460)
_pull # bare, unmangled — single occurrence
_perry_fn_node_modules_effect_src_Order_ts__Order # namespace-pattern Order.Order
_perry_fn_node_modules_effect_src_SchemaAST_ts__Union # `export class Union`
_perry_fn_node_modules_effect_src_internal_channel_subexecutor_ts__Emit # `export class Emit`
Bug 1 — bare _pull symbol (no module prefix)
"_pull", referenced from:
_perry_closure_node_modules_effect_src_internal_stream_ts__1115
_perry_closure_node_modules_effect_src_internal_stream_ts__1121
_perry_closure_node_modules_effect_src_internal_stream_ts__1125
... (~7 closures, all in internal/stream.ts)
Source: effect/src/internal/stream.ts defines const pull = (...) => { ... } as a local arrow function inside three different exported functions (lines 7839, 8114, 8516). Closures inside those functions capture pull — and the captured reference is being emitted as the bare LLVM symbol _pull without the _perry_closure_<module>_<n> or _perry_local_<scope>_pull mangling.
Two follow-on questions:
- Why no module prefix? (probable bug: closure-capture path for nested-arrow
const-bound functions falls back to the raw identifier.)
- The same name
pull is bound three times in disjoint scopes in the same file — even after mangling is fixed, codegen needs to keep them distinct. Likely already handled by closure-id, but worth confirming once the prefix is restored.
Bug 2 — class-as-function references (Union, Emit, Order)
SchemaAST.ts:1709 declares export class Union<M>. internal/channel/subexecutor.ts:215 declares export class Emit<R>. The link errors reference these as _perry_fn_<module>__Union / __Emit — i.e., codegen emits a function reference at the call site for what is in source a class.
Likely scenarios:
- The reference site sees
Union(...) (called without new) — TS allows this for class if a constructor signature is callable, but Perry's mangling needs to look up the class registry rather than emit _perry_fn_.
- Or: the reference is on the type side (
Order.Order) and the type-only import path is leaking into value-position symbol emission.
Order.ts has no export const Order — only export interface OrderTypeLambda and a bunch of named arrow functions. The reference _perry_fn_..._Order_ts__Order originating from DateTime_ts__init, Fiber_ts__init, LogLevel_ts__init smells like the namespace-pattern import type * as order from \"./Order.js\" — Effect uses Order.Order in TS-type position throughout, and one of those references is probably being lowered to a value emit by mistake.
Reproduction
Same as #321 / #460:
cd /tmp/effect-compat && perry compile test_minimal.ts -o /tmp/effect_out
# After #460 lands, only the symbols above will remain undefined.
Suggested investigation order
_pull first — most likely a single-line fix in the closure-capture mangling path; small blast radius.
Union / Emit next — single test case (any class referenced without new) should reproduce in isolation.
Order last — probably depends on type-only-import leak fixes already in flight.
Cross-references
Symptom
After #460 (contextual-keyword re-exports) lands, the link of the Effect repro from #321 still fails on ~7 missing symbols that don't fit the keyword pattern. Filing as a single investigation bucket since they likely share root causes (mangling / class-vs-function emission) and are easier to triage together than as 7 micro-issues.
Missing symbols (post-#460)
Bug 1 — bare
_pullsymbol (no module prefix)Source:
effect/src/internal/stream.tsdefinesconst pull = (...) => { ... }as a local arrow function inside three different exported functions (lines 7839, 8114, 8516). Closures inside those functions capturepull— and the captured reference is being emitted as the bare LLVM symbol_pullwithout the_perry_closure_<module>_<n>or_perry_local_<scope>_pullmangling.Two follow-on questions:
const-bound functions falls back to the raw identifier.)pullis bound three times in disjoint scopes in the same file — even after mangling is fixed, codegen needs to keep them distinct. Likely already handled by closure-id, but worth confirming once the prefix is restored.Bug 2 — class-as-function references (
Union,Emit,Order)SchemaAST.ts:1709declaresexport class Union<M>.internal/channel/subexecutor.ts:215declaresexport class Emit<R>. The link errors reference these as_perry_fn_<module>__Union/__Emit— i.e., codegen emits a function reference at the call site for what is in source a class.Likely scenarios:
Union(...)(called withoutnew) — TS allows this forclassif a constructor signature is callable, but Perry's mangling needs to look up the class registry rather than emit_perry_fn_.Order.Order) and the type-only import path is leaking into value-position symbol emission.Order.tshas noexport const Order— onlyexport interface OrderTypeLambdaand a bunch of named arrow functions. The reference_perry_fn_..._Order_ts__Orderoriginating fromDateTime_ts__init,Fiber_ts__init,LogLevel_ts__initsmells like the namespace-patternimport type * as order from \"./Order.js\"— Effect usesOrder.Orderin TS-type position throughout, and one of those references is probably being lowered to a value emit by mistake.Reproduction
Same as #321 / #460:
Suggested investigation order
_pullfirst — most likely a single-line fix in the closure-capture mangling path; small blast radius.Union/Emitnext — single test case (any class referenced withoutnew) should reproduce in isolation.Orderlast — probably depends on type-only-import leak fixes already in flight.Cross-references
export { local as keyword }re-exports don't emit definitions for contextual-keyword names (void/async/await/try/delete/continue) #460 (contextual-keyword re-exports — fix this before this issue, since the keyword bugs dominate the link error count and may be masking smaller issues)@perry_class_keys_<module>__<ClassName>symbol-name collisions when the same class name appears twice in one module #336 (@perry_class_keys_<module>__<ClassName>collision) and state.rs format_value doesn't handle NaN-boxed strings on Windows / Android / GTK4 — string-typed states render as 'NaN' through stateBindTextNumeric / TEXT_BINDINGS #443 (NaN-boxed-string mis-detection in formatting) — both class-mangling-adjacent