Skip to content

fix(codegen): coerce declared-only addition results - #7851

Merged
proggeramlug merged 3 commits into
mainfrom
fix/7506-pshape-fallback-coercion
Aug 11, 2026
Merged

fix(codegen): coerce declared-only addition results#7851
proggeramlug merged 3 commits into
mainfrom
fix/7506-pshape-fallback-coercion

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix the raw-f64 guard-failure path for typed receiver methods when a declared-number + result feeds another arithmetic operator.

After the field guard falls back to a $pshape clone, this.x + this.y can correctly produce a boxed string when a runtime field violates its declared numeric type. Two paths then lost that fact:

  • a TypeScript-inferred numeric local such as const sum = this.x + this.y was not marked declared-only because the tracker only covered Any -> Number refinements;
  • a direct compound operand such as (this.x + this.y) * scale was excluded because residual coercion only consulted declared-only proof for LocalGet.

This change propagates declared-only proof into every numeric local whose initializer carries it, and consults the same proof for every arithmetic operand. Proven raw-f64 tiers still answer false and remain coercion-free.

The existing clone-composition test now asserts the semantic order dynamic + -> ToNumber -> multiply and that the typed raw-f64 clone retains no dynamic add or number coercion. A parsed TypeScript parity regression covers both intermediate-local and direct-expression forms through the actual $pshape fallback.

Reproduction

Both compiler arms linked generated programs against the same runtime:

pre-fix Perry: 12 string 12 string
fixed Perry:   36 number 36 number
Node:          36 number 36 number

Validation

  • cargo test -p perry-codegen --test native_proof_regressions -- --test-threads=1 — 262 passed
  • focused typed_f64_receiver_method_clone_raw_loads_after_composed_guards — passed
  • release compiler build — passed
  • two-compiler / one-runtime executable A/B — fixed output matches Node
  • python3 scripts/check_test_registration.py — passed
  • cargo fmt --all -- --check — passed
  • bash scripts/check_file_size.sh — passed
  • cargo test -p perry-codegen — 877 library tests passed, then stopped at the documented pre-existing large_local_array_push_inbounds_store_emits_precise_slot_barrier failure

Closes #7506.

Summary by CodeRabbit

  • Bug Fixes

    • Improved numeric coercion for calculations involving declared numeric fields, compound expressions, and values that change type at runtime.
    • Fixed arithmetic when numeric fields are replaced with strings, ensuring results are coerced correctly before subsequent calculations.
    • Preserved optimized behavior for values already proven to be valid numbers.
  • Tests

    • Added regression coverage for regular and inline method calls, runtime type changes, and fallback arithmetic behavior.

@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: 5d826d16-5044-4cc1-ad4e-85030980e2f3

📥 Commits

Reviewing files that changed from the base of the PR and between 2c5a4ef and 6903f0b.

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

📝 Walkthrough

Walkthrough

The compiler extends declared-only numeric proof tracking to numeric locals and compound expressions. Residual coercion now preserves JavaScript semantics in typed-receiver fallbacks. Regression tests verify coercion and fallback ordering.

Changes

Declared-only numeric coercion

Layer / File(s) Summary
Declared-only proof tracking
crates/perry-codegen/src/stmt/let_stmt.rs, crates/perry-codegen/src/type_analysis/pod.rs, crates/perry-codegen/src/expr/mod.rs
Numeric locals from declared-only initializers are tracked for refined and directly numeric types. Documentation comments describe compound expressions and boxed-value propagation.
Residual coercion and regression coverage
crates/perry-codegen/src/expr/binary.rs, crates/perry-codegen/tests/native_proof_regressions.rs, test-files/test_gap_7506_pshape_add_result_coercion.ts, changelog.d/7851-pshape-add-result-coercion.md
Residual coercion now uses numeric_proof_is_declared_only. Regression checks validate dynamic addition, js_number_coerce, multiplication ordering, poisoned numeric fields, and typed receiver fallback behavior. The changelog records the coercion fix.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NumericLocal
  participant operand_needs_residual_coerce
  participant js_number_coerce
  participant ReceiverFallback
  NumericLocal->>operand_needs_residual_coerce: provide declared-only numeric expression
  operand_needs_residual_coerce->>js_number_coerce: coerce residual numeric value
  ReceiverFallback->>js_number_coerce: coerce dynamic addition result
  js_number_coerce-->>ReceiverFallback: return numeric value for multiplication
Loading

Possibly related PRs

  • PerryTS/perry#7831: Extends the same declared-only numeric proof and residual coercion paths.
  • PerryTS/perry#7842: Also updates numeric operator lowering and declaration-only proof handling.
  • PerryTS/perry#7669: Updates numeric-proof and arithmetic lowering in the same codegen area with a different proof source.

Suggested labels: bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main code generation fix.
Description check ✅ Passed The description explains the problem, solution, affected behavior, linked issue, and validation results.
Linked Issues check ✅ Passed The changes address issue #7506 by validating composed guard behavior and preserving a correct dynamic fallback for guard failures.
Out of Scope Changes check ✅ Passed The code, documentation, regression tests, test fixture, and changelog entry all support the stated issue and PR objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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/7506-pshape-fallback-coercion

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: 1

🤖 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/tests/native_proof_regressions.rs`:
- Around line 11746-11751: Update the regression assertions around the cond_br
consuming js_typed_feedback_class_field_get_guard so the typed clone is required
only in the guard-success successor and explicitly rejected in the failure
successor. Replace the unconditional call-pattern check that currently accepts
any i64 receiver with successor-specific validation, ensuring $typed_f64_recv
cannot appear on the failed field-guard path while preserving the existing
coercion checks there.
🪄 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: 343d855e-de06-466e-91ec-4242610d1557

📥 Commits

Reviewing files that changed from the base of the PR and between 079e646 and d091765.

📒 Files selected for processing (6)
  • crates/perry-codegen/src/expr/binary.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/stmt/let_stmt.rs
  • crates/perry-codegen/src/type_analysis/pod.rs
  • crates/perry-codegen/tests/native_proof_regressions.rs
  • test-files/test_gap_7506_pshape_add_result_coercion.ts

Comment thread crates/perry-codegen/tests/native_proof_regressions.rs
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.

typed_f64_receiver_method_clone_raw_loads_after_composed_guards: the guard-failure edge no longer calls $generic — miscompile or intentional collapse?

1 participant