Summary
A spread method call whose receiver is an imported binding (arr.map(...[cb]) where arr comes from another module) produces wrong results or throws. Pre-existing on d8be5f4a2; the failure shape changes with #7188 but it is wrong in both arms.
Repro
lib.ts
export const arr = [3, 1, 2];
export const nums: number[] = [10, 20, 30];
main.ts
import { arr, nums } from "./lib.ts";
const cb = (x: number) => x * 2;
console.log(JSON.stringify(arr.map(...([cb] as [any]))));
console.log(JSON.stringify(arr.slice(...([1, 3] as [any, any]))));
console.log(JSON.stringify(nums.join(...(["-"] as [any]))));
console.log(JSON.stringify(nums.includes(...([20] as [any]))));
| case |
node 26.5.1 |
perry d8be5f4a2 |
perry with #7188 |
arr.map(...[cb]) |
[6,2,4] |
TypeError: object is not a function |
TypeError: Cannot convert undefined or null to object |
arr.slice(...[1,3]) |
[1,2] |
[3,1,2] (silently wrong) |
[] |
nums.join(...["-"]) |
"10-20-30" |
TypeError: Cannot convert undefined or null to object |
same |
nums.includes(...[20]) |
true |
false (silently wrong) |
TypeError: Cannot convert undefined or null to object |
4/4 wrong before, 4/4 wrong after — #7188 is not a regression here, but two cases move from a silently-wrong value to a throw, and one moves from one wrong value to another.
Where it comes from
crates/perry-hir/src/lower/expr_call/imported_array_methods.rs carries a note from #6718:
a spread method call on an IMPORTED array … is intentionally NOT declined here … The imported binding lowers to an ExternFuncRef receiver, which that [generic Expr::CallSpread] tail's member-callee arm skips (it may be an imported function), so routing there would fail to dispatch the native method.
That is the bug: the generic CallSpread tail declines member callees on ExternFuncRef receivers, so the spread call never dispatches the receiver's method. The imported-array fold was papering over it — and it papered badly (slice/includes were already returning wrong values, since the spread argument list arrives as a single array in the builtin's first slot). The test_gap_6718_spread_call_native_method repro covers inline literals, local receivers and queueMicrotask — not imported receivers — so this has never been under test.
Fix belongs in the CallSpread member-callee arm: let it dispatch on an ExternFuncRef receiver instead of skipping.
Environment
Node 26.5.1 (.node-version pin), perry @ d8be5f4a2, macOS arm64, PERRY_NO_AUTO_OPTIMIZE=1. Found while investigating #7154 / #7188.
Refs #7154, #7188, #6718.
Summary
A spread method call whose receiver is an imported binding (
arr.map(...[cb])wherearrcomes from another module) produces wrong results or throws. Pre-existing ond8be5f4a2; the failure shape changes with #7188 but it is wrong in both arms.Repro
lib.tsmain.tsd8be5f4a2arr.map(...[cb])[6,2,4]TypeError: object is not a functionTypeError: Cannot convert undefined or null to objectarr.slice(...[1,3])[1,2][3,1,2](silently wrong)[]nums.join(...["-"])"10-20-30"TypeError: Cannot convert undefined or null to objectnums.includes(...[20])truefalse(silently wrong)TypeError: Cannot convert undefined or null to object4/4 wrong before, 4/4 wrong after — #7188 is not a regression here, but two cases move from a silently-wrong value to a throw, and one moves from one wrong value to another.
Where it comes from
crates/perry-hir/src/lower/expr_call/imported_array_methods.rscarries a note from #6718:That is the bug: the generic
CallSpreadtail declines member callees onExternFuncRefreceivers, so the spread call never dispatches the receiver's method. The imported-array fold was papering over it — and it papered badly (slice/includeswere already returning wrong values, since the spread argument list arrives as a single array in the builtin's first slot). Thetest_gap_6718_spread_call_native_methodrepro covers inline literals, local receivers andqueueMicrotask— not imported receivers — so this has never been under test.Fix belongs in the
CallSpreadmember-callee arm: let it dispatch on anExternFuncRefreceiver instead of skipping.Environment
Node 26.5.1 (
.node-versionpin), perry @d8be5f4a2, macOS arm64,PERRY_NO_AUTO_OPTIMIZE=1. Found while investigating #7154 / #7188.Refs #7154, #7188, #6718.