Files
scriptc/tests/diagnostics/inheritance.ts
Chris Tate 009a24b469 Field redeclares, class destructuring, unknown-field completion, node:module fence
- redeclaring an inherited field WITH an initializer lowers as the [[Define]]-equivalent assignment into the base slot at the subclass's field-init position (builtin Error prefix included — prettier's errors.js `name = "ConfigError"`); bare and type-changing redeclares keep sharpened fences (corpus 2428, diagnostics inheritance re-record)
- object destructuring of CLASS instances desugars to one member read per element, left to right: fields read slots, accessors call getters through the fieldGetExpr dispatch, renames/parameter patterns/defaults included (corpus 2429 — prettier's AstPath { previous, next })
- an object literal missing an 'unknown' field completes with the DOM undefined (the absent-property read's answer), at literal completion and in the record width relation (corpus 2430 — prettier's getFileInfo(file, {}))
- node:module joins the supported builtins prefix-only as an admit-then-fence surface: createRequire keeps a per-member fence that defers to a catchable runtime error in JS sources (diagnostics create-require pins the hint naming the pattern)
2026-07-22 23:48:01 -05:00

94 lines
2.6 KiB
TypeScript

// Inheritance edges the compiler rejects (tsc-clean, outside the subset).
class Animal {
name: string = "a";
speak(): string {
return this.name;
}
feed(other: Animal): string {
return other.name;
}
}
// abstract classes compile; abstract PROPERTY declarations are erased at
// runtime (no shared slot exists), so reads through abstract-typed
// receivers keep a named fence
abstract class Base {
abstract kind(): string;
abstract limit: number;
usesLimit(): number {
return this.limit;
}
}
class Impl extends Base {
limit = 5;
kind(): string {
return "i";
}
}
// abstract GENERIC methods have no body to monomorphize
abstract class GenericAbstract {
abstract pick<T>(x: T): T;
}
// extends must name a class the frontend can pin exactly: const aliases
// holding one class compile now (classes are values), but a REASSIGNABLE
// binding could hold any class at evaluation — the base stays a fence.
let AnimalAlias = Animal;
class Aliased extends AnimalAlias {}
// redeclaring an inherited field: the slot-type-exact WITH-initializer form
// lowers (corpus 2428); the BARE form (type stripping leaves `name;`, which
// Node [[Define]]s back to undefined) and the type-changing form keep fences
class BareRepeat extends Animal {
// @ts-expect-error — tsc flags the overwrite (TS2612); the fence names Node's undefined reset
name!: string;
}
class RetypedRepeat extends Animal {
// @ts-expect-error — tsc rejects the incompatible redeclare too; the fence names the reason
name: number = 2;
}
// overrides must keep the exact signature (method bivariance is unsound
// through a vtable)
class Bivariant extends Animal {
feed(other: Bivariant): string {
return other.name;
}
}
// super() must be a top-level constructor statement
class Conditional extends Animal {
constructor(flag: boolean) {
if (flag) {
super();
} else {
super();
}
}
}
// instanceof needs a class instance on the left...
const rec = { name: "r" };
console.log(rec instanceof Animal);
// ...and folds statically for standalone classes, so a computed operand
// whose effects would be dropped is rejected
class Point {
x: number = 0;
}
console.log(new Point() instanceof Point);
// Reached: unreached bodies never lower, so their rejections only exist
// when something on the entry path uses them.
new Conditional(true);
// Reached: collection defers its diagnostics until a reference makes
// them relevant; these references are what makes them count.
new Impl().usesLimit();
const gaRef = GenericAbstract;
new Aliased();
new BareRepeat();
new RetypedRepeat();
new Bivariant();