Summary
A cross-package (compilePackages) function that uses arguments returns
undefined for calls with fewer args than the inflated param count.
Perry appends a synthetic arguments param (name: "arguments", is_rest: true)
to any function whose body references arguments (#677). Cross-package, the
importer's param-count collection (compile.rs ~606, func.params.len())
counts that synthetic param as a real one, inflating the arity, and the
cross-module call mishandles it (the synthetic arguments is treated as a
trailing-rest collecting only args after the fixed params, instead of the full
argument list). Under-filled calls then return undefined.
Minimal repro (compilePackages)
node_modules/mypkg/src/index.ts:
export function usesArgs(a: number, b?: number): number {
return arguments.length === 1 ? a : a + (b as number);
}
export function noArgs(a: number, b?: number): number {
return b === undefined ? a : a + b;
}
entry (perry.compilePackages: ["mypkg"]):
import { usesArgs, noArgs } from "mypkg";
console.log(usesArgs(5), usesArgs(5, 3), noArgs(5), noArgs(5, 3));
|
node |
perry |
usesArgs(5) |
5 |
undefined ✗ |
usesArgs(5,3) |
8 |
8 |
noArgs(5) |
5 |
5 |
noArgs(5,3) |
8 |
8 |
--print-hir on the entry: usesArgs (params: 3) vs noArgs (params: 2) — the
synthetic arguments param inflates usesArgs to 3. Single-file (non-package)
arguments-using functions work; only the cross-package path is broken.
Impact — the #321 (Effect framework) gateway blocker
effect's pipe and dual (the two most-used combinators) both use arguments,
so cross-package they return undefined. This cascades:
pipe(a, fn) → undefined
Effect.map / Effect.pipe → _op of undefined in the fiber runtime
S.Struct({...}) decode → _tag of undefined in ParseResult
- effect's runtime init:
liveServices = pipe(Context.empty(), Context.add(...)…)
→ undefined → currentServices.initial undefined →
FiberRuntime.refreshRefCache → .unsafeMap of undefined.
The effect DoD (deep import, Schema init, S.Number decode, import { Effect }
barrel Effect.runSync(Effect.succeed(42))) already works (#1804/#1809/#1810/
#1811/#1812/#1815) because those paths don't depend on a pipe/arguments
result. This bug is the gateway to the rest of effect.
Fix direction
The cross-module param count + call must treat the synthetic arguments param
specially: exclude it from the user-visible arity, and populate it with the
full argument list (as the same-module synthetic-arguments path does), not
as a trailing rest. Sites: compile.rs exported-func param-count collection +
the cross-module call lowering's rest/arity handling. Broad blast radius
(all cross-module calls to arguments-using functions) — needs a thorough
regression sweep.
Refs #321, #1758, #677.
Summary
A cross-package (compilePackages) function that uses
argumentsreturnsundefinedfor calls with fewer args than the inflated param count.Perry appends a synthetic
argumentsparam (name: "arguments", is_rest: true)to any function whose body references
arguments(#677). Cross-package, theimporter's param-count collection (
compile.rs~606,func.params.len())counts that synthetic param as a real one, inflating the arity, and the
cross-module call mishandles it (the synthetic
argumentsis treated as atrailing-rest collecting only args after the fixed params, instead of the full
argument list). Under-filled calls then return
undefined.Minimal repro (compilePackages)
node_modules/mypkg/src/index.ts:entry (
perry.compilePackages: ["mypkg"]):usesArgs(5)usesArgs(5,3)noArgs(5)noArgs(5,3)--print-hiron the entry:usesArgs (params: 3)vsnoArgs (params: 2)— thesynthetic
argumentsparam inflatesusesArgsto 3. Single-file (non-package)arguments-using functions work; only the cross-package path is broken.Impact — the #321 (Effect framework) gateway blocker
effect's
pipeanddual(the two most-used combinators) both usearguments,so cross-package they return
undefined. This cascades:pipe(a, fn)→ undefinedEffect.map/Effect.pipe→_opof undefined in the fiber runtimeS.Struct({...})decode →_tagof undefined in ParseResultliveServices = pipe(Context.empty(), Context.add(...)…)→ undefined →
currentServices.initialundefined →FiberRuntime.refreshRefCache→.unsafeMapof undefined.The effect DoD (deep import, Schema init,
S.Numberdecode,import { Effect }barrel
Effect.runSync(Effect.succeed(42))) already works (#1804/#1809/#1810/#1811/#1812/#1815) because those paths don't depend on a
pipe/argumentsresult. This bug is the gateway to the rest of effect.
Fix direction
The cross-module param count + call must treat the synthetic
argumentsparamspecially: exclude it from the user-visible arity, and populate it with the
full argument list (as the same-module synthetic-arguments path does), not
as a trailing rest. Sites:
compile.rsexported-func param-count collection +the cross-module call lowering's rest/arity handling. Broad blast radius
(all cross-module calls to
arguments-using functions) — needs a thoroughregression sweep.
Refs #321, #1758, #677.