Skip to content

fix(codegen): #836 — emit producer aliases for $-prefixed re-exports and namespace wrappers#883

Merged
proggeramlug merged 2 commits into
mainfrom
fix-836-zod-class-reexports
May 16, 2026
Merged

fix(codegen): #836 — emit producer aliases for $-prefixed re-exports and namespace wrappers#883
proggeramlug merged 2 commits into
mainfrom
fix-836-zod-class-reexports

Conversation

@proggeramlug
Copy link
Copy Markdown
Contributor

Summary

  • Closes the zod compilePackages link surface. 82 → 1 undefined symbols on the canonical repro (perry.compilePackages: ["zod"]; import { z } from "zod";).
  • Sub-bug A: producer-side sanitize() rewrites $_, so export const $ZodCheck lands at perry_fn_<src>___ZodCheck while consumer-side import_origin_suffix() returns names verbatim → perry_fn_<src>__$ZodCheck reference link-fails. Fix emits raw-name aliases when sanitize(exported) != exported.
  • Sub-bug B: import * as z from "…"; export { z }; produces Export::Named { local: "z", exported: "z" } which every wrapper-emission loop skipped. Fix emits a no-op __perry_wrap_perry_fn_<src>__<exported> for local == exported exports whose local is not a HIR function.

Remaining undefined symbol on zod (_perry_fn_..._en_ts__default, from export default function () {…}) is a separate HIR-lowerer bug, out of scope here.

Test plan

  • cargo build --release -p perry-runtime -p perry-stdlib -p perry clean
  • cargo test --release --workspace --exclude perry-ui-* --exclude perry-jsruntime — all pass, no regressions
  • New regression test test-files/test_issue_836_zod_class_reexports.ts + test-files/fixtures/issue_836_pkg/ compiles and runs byte-for-byte vs. node --experimental-strip-types
  • User-level zod repro advances from 82 undefined symbols to 1 (the separate anonymous-default bug)
  • Existing related tests (test_issue_678_reexport_default.ts, test_issue_838_prototype_methods.ts) still pass

…orts and namespace-import wrappers

Two link-time failures in the zod compilePackages repro:

1. Sanitize mismatch — `export const $ZodCheck = …` lands at
   `perry_fn_<src>___ZodCheck` (producer-side `sanitize()` rewrites `$`
   to `_`), but consumer-side `import_origin_suffix()` returns the
   exported name verbatim, so consumer references
   `perry_fn_<src>__$ZodCheck` and link-fails. Same mismatch hits the
   `__perry_wrap_perry_fn_<src>__$ZodCheck` closure-wrapper symbol.

2. `local == exported` non-function exports — `import * as z from
   "…"; export { z };` produces `Export::Named { local: "z", exported:
   "z" }`, which every wrapper-emission loop skipped (regular
   `__perry_wrap_<fn>` loop keys on `hir.functions`; the v0.5.916 #837
   rename loop filters on `local != exported`). Consumers that read
   `z` as a value link-failed on `__perry_wrap_perry_fn_<index_ts>__z`.

Fix: new emission block in `crates/perry-codegen/src/codegen.rs`
right after the #837 renamed-wrapper loop. For every `Export::Named
{ local, exported }` it emits two kinds of aliases as needed:

- Raw-name aliases when `sanitize(exported) != exported`:
  `perry_fn_<src>__<raw_exported>` forwards to the sanitized
  symbol; `__perry_wrap_perry_fn_<src>__<raw_exported>` forwards to
  the sanitized wrapper or no-ops to undefined.

- No-op `__perry_wrap_perry_fn_<src>__<exported>` for `local ==
  exported` exports whose local is not a HIR function.

LLVM IR allows `$` unquoted in identifiers per LangRef, so raw-name
aliases serialize without quoting changes. Both alias paths are
idempotent (HashSet + `llmod.has_function`).

Effect on the zod repro: 82 → 1 undefined symbols. The remaining one
(`_perry_fn_..._en_ts__default`) comes from anonymous `export default
function () {…}` getting dropped by the HIR lowerer — separate bug,
out of scope here.

Validation: new regression test
`test-files/test_issue_836_zod_class_reexports.ts` with fixture
`test-files/fixtures/issue_836_pkg/` mirrors the failing zod shape
self-contained. Output is byte-for-byte vs.
`node --experimental-strip-types`. Workspace tests pass.

Refs #836, #793, #805, #837.
@proggeramlug proggeramlug force-pushed the fix-836-zod-class-reexports branch from f0d6161 to 407619e Compare May 16, 2026 21:45
@proggeramlug proggeramlug merged commit 0dfedb5 into main May 16, 2026
9 checks passed
@proggeramlug proggeramlug deleted the fix-836-zod-class-reexports branch May 16, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant