Skip to content

fix(codegen): tag-guard String methods on Any receivers - #7866

Merged
proggeramlug merged 1 commit into
mainfrom
fix/7673-positive-string-fastpath
Aug 11, 2026
Merged

fix(codegen): tag-guard String methods on Any receivers#7866
proggeramlug merged 1 commit into
mainfrom
fix/7673-positive-string-fastpath

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • evaluate an unproven method receiver once and test its heap-string/SSO NaN-box tag
  • keep tag-proven strings on direct String lowering while routing objects with colliding names through universal method dispatch
  • remove the method-name/arity and class-blocklist heuristics that mis-lowered z.string().trim()
  • preserve the existing statically proven String, Array, built-in, and known-class dispatch paths

Reproduction

The regression program covers a schema-like object whose trim, split, and min methods return the object, plus 18 String methods on an opaque any string. The fixed binary matches Node byte-for-byte across all 22 output rows.

Performance

Measured on the locked M1 mini with both compilers linked against the same unchanged baseline runtime. The benchmark runs 30,000,000 charCodeAt calls on a string hidden behind JSON.parse(process.argv[2]); 30 alternating runs after two warmups per binary:

case baseline wall fixed wall delta
Any receiver 0.210294s 0.149391s -29.0%
typed control 0.031693s 0.031518s -0.6%

User-time deltas were -29.2% and -0.1%, respectively. The improvement comes from proving the runtime tag once and skipping the old per-call coercion.

Tests

  • cargo test -p perry-codegen --lib (889 passed)
  • cargo test -p perry-codegen --test argless_builtin_extra_args (3 passed)
  • python3 scripts/check_test_registration.py
  • bash scripts/check_file_size.sh
  • functional output comparison against Node

Closes #7673

Summary by CodeRabbit

  • Bug Fixes

    • Corrected method dispatch for String-named calls on any values.
    • User-defined methods now take precedence on objects, while actual strings retain optimized String behavior.
    • Improved handling of runtime strings, callbacks, chained methods, and extra arguments.
  • Tests

    • Added regression coverage for method-name collisions and runtime type-based dispatch.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 784fbd66-7920-4eb8-a1e7-7ff16e459753

📥 Commits

Reviewing files that changed from the base of the PR and between 631c921 and 85c46f6.

📒 Files selected for processing (3)
  • crates/perry-codegen/src/lower_call/property_get.rs
  • crates/perry-codegen/src/lower_call/property_get/helpers.rs
  • crates/perry-codegen/tests/argless_builtin_extra_args.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry-codegen/src/lower_call/property_get.rs

📝 Walkthrough

Walkthrough

String method lowering now checks runtime String tags before using String builtins. Other any receivers use generic native method dispatch. Receiver evaluation occurs once, and regression tests cover runtime strings and user-defined method collisions.

Changes

Any String method dispatch

Layer / File(s) Summary
Dispatch primitives
crates/perry-codegen/src/lower_string_method.rs, crates/perry-codegen/src/lower_call/console_promise.rs
String lowering accepts proven receiver boxes. Native method dispatch centralizes dispatch IDs, argument marshaling, feedback, and call metadata.
Tag-guarded receiver integration
crates/perry-codegen/src/lower_call/property_get.rs, crates/perry-codegen/src/lower_call/property_get/helpers.rs
Unproven receivers are evaluated once. String-tagged values use String lowering. Other values use generic native dispatch instead of unconditional String dispatch.
Regression validation and release note
crates/perry-codegen/tests/argless_builtin_extra_args.rs, test-files/test_gap_7673_any_string_method_collision.ts, changelog.d/7866-any-string-method-dispatch.md
Tests cover any receivers, runtime strings, String method lowering, user-defined collisions, and schema chaining. The changelog records the dispatch correction.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant PropertyGetLowering
  participant StringMethodLowering
  participant NativeMethodDispatcher
  Caller->>PropertyGetLowering: invoke String-named method
  PropertyGetLowering->>PropertyGetLowering: evaluate receiver and inspect runtime tags
  PropertyGetLowering->>StringMethodLowering: lower proven String receiver
  PropertyGetLowering->>NativeMethodDispatcher: dispatch unproven or non-String receiver
  NativeMethodDispatcher-->>Caller: return method result
Loading

Possibly related PRs

  • PerryTS/perry#6842: Reuses static dispatch ID generation and extends runtime-tagged any String-method dispatch.
  • PerryTS/perry#7601: Both changes modify String-method lowering, with this PR focused on runtime dispatch for any receivers.

Suggested reviewers: thehypnoo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the code-generation fix for tag-guarded String method dispatch on Any receivers.
Description check ✅ Passed The description is mostly complete and covers the change, issue reference, tests, regression behavior, and performance impact.
Linked Issues check ✅ Passed The implementation addresses all coding objectives in [#7673], including tag guards, single receiver evaluation, runtime dispatch, and collision coverage.
Out of Scope Changes check ✅ Passed The code, regression tests, benchmark data, and changelog entry all support the linked issue and stated String dispatch objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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/7673-positive-string-fastpath

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-codegen/src/lower_call/property_get.rs`:
- Around line 51-57: The tag-based String lowering guard in the property-get
lowering logic must also validate call arity. For known String method names,
bypass this guard when args.len() falls outside the selected method’s accepted
arity, allowing the generic dispatcher to handle non-string receivers while
preserving String lowering for valid arities; update the condition surrounding
lower_string_method_from_proven_box and reuse the existing method-arity matching
logic.

In `@test-files/test_gap_7673_any_string_method_collision.ts`:
- Around line 1-53: Run the gap test with Node v26.5.1, matching the version
pinned by .node-version, rather than the current Node v24.15.0 environment.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: be0ca6c3-2e30-4162-880a-c091cedc9bf1

📥 Commits

Reviewing files that changed from the base of the PR and between ed97b9c and 631c921.

📒 Files selected for processing (7)
  • changelog.d/7866-any-string-method-dispatch.md
  • crates/perry-codegen/src/lower_call/console_promise.rs
  • crates/perry-codegen/src/lower_call/property_get.rs
  • crates/perry-codegen/src/lower_call/property_get/helpers.rs
  • crates/perry-codegen/src/lower_string_method.rs
  • crates/perry-codegen/tests/argless_builtin_extra_args.rs
  • test-files/test_gap_7673_any_string_method_collision.ts
💤 Files with no reviewable changes (1)
  • crates/perry-codegen/src/lower_call/property_get/helpers.rs

Comment thread crates/perry-codegen/src/lower_call/property_get.rs
Comment thread test-files/test_gap_7673_any_string_method_collision.ts
@proggeramlug
proggeramlug force-pushed the fix/7673-positive-string-fastpath branch from 631c921 to 85c46f6 Compare August 11, 2026 17:16
@proggeramlug
proggeramlug merged commit 7aa80cd into main Aug 11, 2026
12 of 19 checks passed
@proggeramlug
proggeramlug deleted the fix/7673-positive-string-fastpath branch August 11, 2026 17:35
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.

z.string().trim() is mis-lowered to String.prototype.trim() on an Any-typed Zod schema

1 participant