mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-31 07:23:06 +08:00
`arguments.length` in a typed function folds to a constant. In a function
declaration it was the declared parameter count even when the function is
called through a value with more arguments: Node prints 4 for
`[1].map(f)` with `function f(v) { return v + arguments.length; }`, the
compiled program printed 2.
A top-level function declaration that reads `arguments` and that the
program uses as a value now gets a count slot. Its value is an adapter
that stores the parameter count of the function type the value is passed
as (3 for map, 4 for reduce, 2 for a sort comparator) and forwards; the
function reads the slot on entry and clears it, so a direct call sees the
declared count.
Function expressions and declarations passed where the expected function
type has optional or rest parameters (a replace callback) are called with
a varying count and are refused with SC1090 instead of folding to a wrong
count, as are methods, nested functions, and arrows inside a function
used as a value.
37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
// `arguments.length` has no single value when the calls pass varying
|
|
// counts: a function expression or declaration passed where the expected
|
|
// function type has optional or rest parameters. Methods and nested
|
|
// functions used as values, and arrows inside a function used as a value,
|
|
// keep the fence.
|
|
const replaced = "a-b".replace(/-/, function (match) {
|
|
return String(arguments.length) + match;
|
|
});
|
|
function call(f: (a: number, b?: number) => number): number {
|
|
return f(1, 2);
|
|
}
|
|
const counted = call(function (a) {
|
|
return arguments.length + a;
|
|
});
|
|
function offset(value: number): number {
|
|
return value + arguments.length;
|
|
}
|
|
const offsets = call(offset);
|
|
class Scale {
|
|
static by(value: number): number {
|
|
return value * arguments.length;
|
|
}
|
|
}
|
|
const scaled = [2].map(Scale.by);
|
|
function outer(): number[] {
|
|
function inner(value: number): number {
|
|
return value + arguments.length;
|
|
}
|
|
return [1].map(inner);
|
|
}
|
|
function deferred(value: number): number {
|
|
const read = (): number => arguments.length;
|
|
return value + read();
|
|
}
|
|
const late = [1].map(deferred);
|
|
export { replaced, counted, offsets, scaled, outer, late };
|