Skip to content

fix(hir): salt class-capture names on the module name, not the absolute path (#7177) - #7806

Merged
proggeramlug merged 1 commit into
mainfrom
fix/7177-cap-salt-reproducible
Aug 11, 2026
Merged

fix(hir): salt class-capture names on the module name, not the absolute path (#7177)#7806
proggeramlug merged 1 commit into
mainfrom
fix/7177-cap-salt-reproducible

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Class-capture symbol names no longer depend on the working directory (#7177) — the same source compiled from two different directories now produces byte-identical IR.

The per-module salt in __perry_cap_<id>m<salt> was an FNV hash of the canonical absolute source path, so it changed with the checkout location. Reproducible builds were impossible by construction, and every IR/object A/B harness had to independently discover the dependency and pin cwd — #7176's byte-neutrality harness measured 29 of 29 same-compiler control runs differing once it used per-run mkdtemp directories.

Reproduced before touching anything: the same 8-line source compiled from two directories differed in exactly 4 lines of IR, all of them the salt string (m000059ddd802 vs m0000f0a10f23). Everything else — including the prog_ts module prefix on every other symbol — was already identical, which is the tell: the module NAME was reproducible all along, and only the salt reached past it to the filesystem.

So the salt now keys on the module name. That is not merely convenient, it is the identity that already satisfies all three properties the salt needs:

  • Reproducible — it is what every other emitted symbol is prefixed with (perry_fn_<mod>__…, perry_global_<mod>__…), so it cannot vary with the checkout without breaking far more than this.
  • Unique per module — it carries directory components, so a/util.ts and b/util.ts become a_util_ts and b_util_ts. Verified with two same-basename modules whose capture stashes must not merge: distinct salts, correct output.
  • Equal within a module — same module ⇒ same salt, so same-module inheritance keeps sharing the parent's capture stash, which is the bug the salt was introduced for.

with_class_id_start keeps its old path-based behaviour for the #[cfg(test)] lowering entry points that have no module name; the production path uses the new with_class_id_start_salted.

Verified: IR byte-identical across two working directories (was: 4 lines differing); same-basename modules keep distinct salts and match Node; test_gap_cap_salt_reproducible_7177.ts passes byte-for-byte. The gap test deliberately covers the properties rather than the reproducibility itself — a .ts test cannot compile itself from two directories — pinning cross-module isolation, same-module inheritance sharing, and two distinct captures in one module, so a future re-keying that is too coarse or too fine fails rather than silently merging stashes. cargo test -p perry-hir 293 passed, cargo test -p perry 902 passed, test_gap_class 24/24.

Summary by CodeRabbit

  • Bug Fixes

    • Generated capability names are now reproducible across different checkout locations.
    • Captures from distinct modules remain isolated, while inherited captures within the same module continue to work correctly.
  • Tests

    • Added coverage for reproducible output, same-basename module isolation, inheritance, and nested captures.
  • Documentation

    • Documented the improved reproducibility behavior.

@proggeramlug
proggeramlug force-pushed the fix/7177-cap-salt-reproducible branch from b289456 to 43ca8fe Compare August 10, 2026 22:07
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The lowering context now derives capture salts from module names instead of absolute source paths. Module lowering uses the new salted constructor. Existing test-only paths retain path-based salting. New tests cover reproducibility, module isolation, inheritance sharing, and distinct captures.

Changes

Capture salt stability

Layer / File(s) Summary
Salt identity contract
crates/perry-hir/src/lower/context.rs
The lowering context hashes a supplied module identity and adds with_class_id_start_salted. The existing constructor retains path-based salting.
Module lowering integration and regression coverage
crates/perry-hir/src/lower/lower_module_fn.rs, test-files/cap_salt_helper_*.ts, test-files/test_gap_cap_salt_reproducible_7177.ts, changelog.d/7806-cap-salt-reproducible.md
Module lowering passes the module name as the salt identity. Tests cover same-basename module isolation, same-module inheritance, and distinct nested captures. The changelog records the behavior and verification.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

  • PerryTS/perry#6647: Both changes modify LoweringContext class-capture lowering infrastructure, including with_class_id_start.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the main change: using the module name instead of the absolute path for class-capture salts.
Description check ✅ Passed The description clearly explains the change, rationale, affected behavior, related issue, and validation results, but it does not follow the template headings.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/7177-cap-salt-reproducible

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug
proggeramlug merged commit b7e1346 into main Aug 11, 2026
12 of 18 checks passed
@proggeramlug
proggeramlug deleted the fix/7177-cap-salt-reproducible branch August 11, 2026 05:24
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