fix(hir): dispatch Array-mutator methods on interface-typed receivers to their own method#5492
Conversation
… to their own method A method call whose name collides with an Array.prototype mutator (push/pop/shift/unshift/splice/sort/reverse/concat) on a receiver whose static type is a (non-class) named type — an interface or a function/factory return type — was eagerly lowered to the array fast path (Expr::ArrayPush / the array.push_single native arm). That reads the plain object header as an ArrayHeader, so an object that merely owns a same-named closure property had its push silently dropped: the call returned a bogus numeric length and the user method never ran. Same class of bug as PerryTS#5139 (which fixed any-typed receivers): HIR lowering's array-only-method fold treated Type::Named as a user receiver only when lookup_class(name) matched a class, so an interface (not a class) fell through. Add LoweringContext::is_interface_type and recognize interface-typed receivers as user objects in both fold paths (local_array_methods and array_only_methods), so the method dispatches through the runtime js_native_call_method, which selects by the receiver's runtime shape (real array -> dense helper; object with an own callable -> that method).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughAdds ChangesInterface receiver guard for array fast-path lowering
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Thanks @machineloop great PR |
Summary
A method whose name collides with an
Array.prototypemutator (push/pop/shift/…),called on a receiver whose static type is a non-class named type (a user
interfaceor afunction/factory return type), was folded to the array fast-path intrinsic instead of the
object's own method — so the call silently no-opped. This extends the #5139 fix (which only
covered
any-typed receivers) to interface-typed and factory-return-typed receivers.Changes
crates/perry-hir/src/lower/context.rs— addLoweringContext::is_interface_type(name)(a name registered in
self.interfaces).crates/perry-hir/src/lower/expr_call/local_array_methods.rsand…/array_only_methods.rs— the
is_user_class_*Type::Namedarm now also acceptsctx.is_interface_type(name), soan interface receiver skips the array-only-method fold and dispatches to its own method.
(Kept the check precise rather than a blanket
Type::Named(_) => true, so TypedArrays —Int8Arrayetc. — still legitimately fold forfill/map; real arrays are neverType::Named.)crates/perry/tests/interface_typed_arraylike_method_dispatch.rs— regression tests.Related issue
Refs #5139 (extends that fix to interface- / factory-return-typed receivers). No dedicated
issue — happy to file one for tracking if preferred.
Test plan
TDD red→green: before the fix the interface cases printed
len=0(thepushwas dropped);after,
len=2. The real-array control (number[]push/pop) still printssum=3 len=2 popped=3.cargo build --release -p perryclean (the crates this change touches). The full--workspacerelease build fails only onwindows-future— a Windows-only transitivedep that can't compile on this macOS host (env limitation, unrelated to this change).
cargo test --workspace …passes — my new tests pass; the suite's only failures(
integer_locals_provenance,functional_batch2_regressions, and ablocklist_addsubnet_prefixTempDir::joincompile break) reproduce identically onclean
mainwithout this change, so they are pre-existing and unrelated.#[test]in the affected crate (crates/perry/tests/)docs/src/— N/A (internal HIR dispatch)Screenshots / output
Checklist
fix:prefix conventionSummary by CodeRabbit
Bug Fixes
Tests