Files
scriptc/tests/diagnostics/function-value-arguments-length.ts
T
Chris Tate aaca1f1e2b Count the arguments a function receives when it is called through a value
`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.
2026-10-22 18:17:48 -05:00

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 };