Files
scriptc/tests/diagnostics/generic-value-bindings.ts
T
Chris Tate 95b0e2132d Call generic members through receivers that are not statically known
Generic arrow properties and generic methods now have an erased runtime
value, their instance with every type parameter bound to unknown. Calls
through a round trip via any, a function result, an array element or a
class-backed interface call that value and convert the result to the
call's type, as JavaScript does. Direct calls on a known definition keep
their monomorphized path.

Fixes #905
Co-authored-by: Konstantin Mikheev <8560582+konmik@users.noreply.github.com>
2026-10-17 18:36:45 -05:00

54 lines
2.0 KiB
TypeScript

// Generic function VALUE fences, named: every shape here keeps the generic
// signature alive where static monomorphization cannot follow.
// A reassigned binding cannot resolve statically — a later write could hold
// a structurally identical function with a different body.
let flip = <T>(x: T): T => x;
flip = <T>(x: T): T => x;
console.log(flip(1));
// An ALIAS binding registers its target (calls through it monomorphize),
// but a USE with no pinning context still keeps the generic signature —
// the value fences at the reference, not the binding.
const id = <T>(x: T): T => x;
const stored = id;
console.log(typeof stored);
// An alias of a REASSIGNED binding never registers: the target's own
// fence reports, and the alias falls back to the ordinary binding story.
const flipAlias = flip;
console.log(flipAlias(5));
// Declared inside a function: instances are module functions and cannot
// capture the enclosing frame.
function outer(): number {
const inner = <T>(x: T): T => x;
return inner(3);
}
console.log(outer());
// An ambient binding of generic function type now compiles to Node's exact
// ReferenceError at the access (the declare-erasure stance — no diagnostic
// here; the optional chain cannot guard the root's own throw).
declare const ambient: undefined | (<T>(f: (a: T) => T) => T);
console.log(ambient?.((n: number) => n) === undefined);
// A call whose RESULT is itself a generic function: the returned signature
// keeps its type parameters and would need the producing call's frame.
const curried = <T>(x: T) => <U>(y: U): string => `${x}|${y}`;
console.log(curried(1)("a"));
// Ambient `declare class` generic methods are signature-only. Through an
// AMBIENT-ROOTED receiver the call now compiles to Node's ReferenceError
// at the root (the declare-const chain stance — no diagnostic here); a
// receiver that exists at runtime keeps the fence.
declare class Amb {
m<T>(x: T): T;
}
declare const amb: Amb;
console.log(amb.m(4));
function throughParam(a: Amb): void {
console.log(a.m(4));
}
throughParam(amb);