mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 03:09:39 -06:00
Fix crash in mixin checking (#62928)
This commit is contained in:
parent
2dfdbbabae
commit
1f5f9f34d3
@ -13212,6 +13212,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function getBaseTypes(type: InterfaceType): BaseType[] {
|
||||
if (!(getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference))) {
|
||||
return emptyArray;
|
||||
}
|
||||
if (!type.baseTypesResolved) {
|
||||
if (pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseTypes)) {
|
||||
if (type.objectFlags & ObjectFlags.Tuple) {
|
||||
@ -35053,28 +35056,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
* In that case we won't consider it used before its declaration, because it gets its value from the superclass' declaration.
|
||||
*/
|
||||
function isPropertyDeclaredInAncestorClass(prop: Symbol): boolean {
|
||||
if (!(prop.parent!.flags & SymbolFlags.Class)) {
|
||||
return false;
|
||||
}
|
||||
let classType: InterfaceType | undefined = getTypeOfSymbol(prop.parent!) as InterfaceType;
|
||||
while (true) {
|
||||
classType = classType.symbol && getSuperClass(classType) as InterfaceType | undefined;
|
||||
if (!classType) {
|
||||
return false;
|
||||
}
|
||||
const superProperty = getPropertyOfType(classType, prop.escapedName);
|
||||
if (superProperty && superProperty.valueDeclaration) {
|
||||
return true;
|
||||
if (prop.parent && prop.parent.flags & SymbolFlags.Class) {
|
||||
const baseTypes = getBaseTypes(getDeclaredTypeOfSymbol(prop.parent) as InterfaceType);
|
||||
if (baseTypes.length) {
|
||||
const superProperty = getPropertyOfType(baseTypes[0], prop.escapedName);
|
||||
return !!(superProperty && superProperty.valueDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSuperClass(classType: InterfaceType): Type | undefined {
|
||||
const x = getBaseTypes(classType);
|
||||
if (x.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return getIntersectionType(x);
|
||||
return false;
|
||||
}
|
||||
|
||||
function reportNonexistentProperty(propNode: Identifier | PrivateIdentifier, containingType: Type, isUncheckedJS: boolean) {
|
||||
|
||||
17
tests/baselines/reference/checkInheritedProperty.errors.txt
Normal file
17
tests/baselines/reference/checkInheritedProperty.errors.txt
Normal file
@ -0,0 +1,17 @@
|
||||
checkInheritedProperty.ts(7,14): error TS2729: Property 'b' is used before its initialization.
|
||||
|
||||
|
||||
==== checkInheritedProperty.ts (1 errors) ====
|
||||
class Base {
|
||||
}
|
||||
|
||||
declare const BaseFactory: new() => Base & { c: string }
|
||||
|
||||
class Derived extends BaseFactory {
|
||||
a = this.b
|
||||
~
|
||||
!!! error TS2729: Property 'b' is used before its initialization.
|
||||
!!! related TS2728 checkInheritedProperty.ts:8:5: 'b' is declared here.
|
||||
b = "abc"
|
||||
}
|
||||
|
||||
26
tests/baselines/reference/checkInheritedProperty.symbols
Normal file
26
tests/baselines/reference/checkInheritedProperty.symbols
Normal file
@ -0,0 +1,26 @@
|
||||
//// [tests/cases/compiler/checkInheritedProperty.ts] ////
|
||||
|
||||
=== checkInheritedProperty.ts ===
|
||||
class Base {
|
||||
>Base : Symbol(Base, Decl(checkInheritedProperty.ts, 0, 0))
|
||||
}
|
||||
|
||||
declare const BaseFactory: new() => Base & { c: string }
|
||||
>BaseFactory : Symbol(BaseFactory, Decl(checkInheritedProperty.ts, 3, 13))
|
||||
>Base : Symbol(Base, Decl(checkInheritedProperty.ts, 0, 0))
|
||||
>c : Symbol(c, Decl(checkInheritedProperty.ts, 3, 44))
|
||||
|
||||
class Derived extends BaseFactory {
|
||||
>Derived : Symbol(Derived, Decl(checkInheritedProperty.ts, 3, 56))
|
||||
>BaseFactory : Symbol(BaseFactory, Decl(checkInheritedProperty.ts, 3, 13))
|
||||
|
||||
a = this.b
|
||||
>a : Symbol(Derived.a, Decl(checkInheritedProperty.ts, 5, 35))
|
||||
>this.b : Symbol(Derived.b, Decl(checkInheritedProperty.ts, 6, 14))
|
||||
>this : Symbol(Derived, Decl(checkInheritedProperty.ts, 3, 56))
|
||||
>b : Symbol(Derived.b, Decl(checkInheritedProperty.ts, 6, 14))
|
||||
|
||||
b = "abc"
|
||||
>b : Symbol(Derived.b, Decl(checkInheritedProperty.ts, 6, 14))
|
||||
}
|
||||
|
||||
37
tests/baselines/reference/checkInheritedProperty.types
Normal file
37
tests/baselines/reference/checkInheritedProperty.types
Normal file
@ -0,0 +1,37 @@
|
||||
//// [tests/cases/compiler/checkInheritedProperty.ts] ////
|
||||
|
||||
=== checkInheritedProperty.ts ===
|
||||
class Base {
|
||||
>Base : Base
|
||||
> : ^^^^
|
||||
}
|
||||
|
||||
declare const BaseFactory: new() => Base & { c: string }
|
||||
>BaseFactory : new () => Base & { c: string; }
|
||||
> : ^^^^^^^^^^
|
||||
>c : string
|
||||
> : ^^^^^^
|
||||
|
||||
class Derived extends BaseFactory {
|
||||
>Derived : Derived
|
||||
> : ^^^^^^^
|
||||
>BaseFactory : Base & { c: string; }
|
||||
> : ^^^^^^^^^^^^ ^^^
|
||||
|
||||
a = this.b
|
||||
>a : string
|
||||
> : ^^^^^^
|
||||
>this.b : string
|
||||
> : ^^^^^^
|
||||
>this : this
|
||||
> : ^^^^
|
||||
>b : string
|
||||
> : ^^^^^^
|
||||
|
||||
b = "abc"
|
||||
>b : string
|
||||
> : ^^^^^^
|
||||
>"abc" : "abc"
|
||||
> : ^^^^^
|
||||
}
|
||||
|
||||
41
tests/baselines/reference/noCrashOnMixin2.errors.txt
Normal file
41
tests/baselines/reference/noCrashOnMixin2.errors.txt
Normal file
@ -0,0 +1,41 @@
|
||||
noCrashOnMixin2.ts(11,33): error TS2370: A rest parameter must be of an array type.
|
||||
noCrashOnMixin2.ts(11,40): error TS1047: A rest parameter cannot be optional.
|
||||
noCrashOnMixin2.ts(14,12): error TS2545: A mixin class must have a constructor with a single rest parameter of type 'any[]'.
|
||||
noCrashOnMixin2.ts(23,9): error TS2674: Constructor of class 'Abstract' is protected and only accessible within the class declaration.
|
||||
|
||||
|
||||
==== noCrashOnMixin2.ts (4 errors) ====
|
||||
// https://github.com/microsoft/TypeScript/issues/62921
|
||||
|
||||
class Abstract {
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args?: any[]) => T;
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS2370: A rest parameter must be of an array type.
|
||||
~
|
||||
!!! error TS1047: A rest parameter cannot be optional.
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
return class extends Base {
|
||||
~~~~~
|
||||
!!! error TS2545: A mixin class must have a constructor with a single rest parameter of type 'any[]'.
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
public trigger() {
|
||||
new Concrete();
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2674: Constructor of class 'Abstract' is protected and only accessible within the class declaration.
|
||||
}
|
||||
}
|
||||
|
||||
53
tests/baselines/reference/noCrashOnMixin2.symbols
Normal file
53
tests/baselines/reference/noCrashOnMixin2.symbols
Normal file
@ -0,0 +1,53 @@
|
||||
//// [tests/cases/compiler/noCrashOnMixin2.ts] ////
|
||||
|
||||
=== noCrashOnMixin2.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/62921
|
||||
|
||||
class Abstract {
|
||||
>Abstract : Symbol(Abstract, Decl(noCrashOnMixin2.ts, 0, 0))
|
||||
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
>Concrete : Symbol(Concrete, Decl(noCrashOnMixin2.ts, 5, 1))
|
||||
>Abstract : Symbol(Abstract, Decl(noCrashOnMixin2.ts, 0, 0))
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args?: any[]) => T;
|
||||
>Constructor : Symbol(Constructor, Decl(noCrashOnMixin2.ts, 8, 1))
|
||||
>T : Symbol(T, Decl(noCrashOnMixin2.ts, 10, 17))
|
||||
>args : Symbol(args, Decl(noCrashOnMixin2.ts, 10, 32))
|
||||
>T : Symbol(T, Decl(noCrashOnMixin2.ts, 10, 17))
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
>Mixin : Symbol(Mixin, Decl(noCrashOnMixin2.ts, 10, 54))
|
||||
>TBase : Symbol(TBase, Decl(noCrashOnMixin2.ts, 12, 15))
|
||||
>Constructor : Symbol(Constructor, Decl(noCrashOnMixin2.ts, 8, 1))
|
||||
>Base : Symbol(Base, Decl(noCrashOnMixin2.ts, 12, 42))
|
||||
>TBase : Symbol(TBase, Decl(noCrashOnMixin2.ts, 12, 15))
|
||||
|
||||
return class extends Base {
|
||||
>Base : Symbol(Base, Decl(noCrashOnMixin2.ts, 12, 42))
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
>Empty : Symbol(Empty, Decl(noCrashOnMixin2.ts, 15, 1))
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
>CrashTrigger : Symbol(CrashTrigger, Decl(noCrashOnMixin2.ts, 18, 1))
|
||||
>Mixin : Symbol(Mixin, Decl(noCrashOnMixin2.ts, 10, 54))
|
||||
>Empty : Symbol(Empty, Decl(noCrashOnMixin2.ts, 15, 1))
|
||||
|
||||
public trigger() {
|
||||
>trigger : Symbol(CrashTrigger.trigger, Decl(noCrashOnMixin2.ts, 20, 41))
|
||||
|
||||
new Concrete();
|
||||
>Concrete : Symbol(Concrete, Decl(noCrashOnMixin2.ts, 5, 1))
|
||||
}
|
||||
}
|
||||
|
||||
68
tests/baselines/reference/noCrashOnMixin2.types
Normal file
68
tests/baselines/reference/noCrashOnMixin2.types
Normal file
@ -0,0 +1,68 @@
|
||||
//// [tests/cases/compiler/noCrashOnMixin2.ts] ////
|
||||
|
||||
=== noCrashOnMixin2.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/62921
|
||||
|
||||
class Abstract {
|
||||
>Abstract : Abstract
|
||||
> : ^^^^^^^^
|
||||
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
>Concrete : Concrete
|
||||
> : ^^^^^^^^
|
||||
>Abstract : Abstract
|
||||
> : ^^^^^^^^
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args?: any[]) => T;
|
||||
>Constructor : Constructor<T>
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>args : any[] | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
>Mixin : <TBase extends Constructor>(Base: TBase) => { new (...args?: any[]): (Anonymous class); prototype: Mixin<any>.(Anonymous class); } & TBase
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>Base : TBase
|
||||
> : ^^^^^
|
||||
|
||||
return class extends Base {
|
||||
>class extends Base { } : { new (...args?: any[]): (Anonymous class); prototype: Mixin<any>.(Anonymous class); } & TBase
|
||||
> : ^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>Base : {}
|
||||
> : ^^
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
>Empty : Empty
|
||||
> : ^^^^^
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
>CrashTrigger : CrashTrigger
|
||||
> : ^^^^^^^^^^^^
|
||||
>Mixin(Empty) : Mixin<typeof Empty>.(Anonymous class)
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>Mixin : <TBase extends Constructor>(Base: TBase) => { new (...args?: any[]): (Anonymous class); prototype: Mixin<any>.(Anonymous class); } & TBase
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>Empty : typeof Empty
|
||||
> : ^^^^^^^^^^^^
|
||||
|
||||
public trigger() {
|
||||
>trigger : () => void
|
||||
> : ^^^^^^^^^^
|
||||
|
||||
new Concrete();
|
||||
>new Concrete() : any
|
||||
> : ^^^
|
||||
>Concrete : typeof Concrete
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
}
|
||||
}
|
||||
|
||||
12
tests/cases/compiler/checkInheritedProperty.ts
Normal file
12
tests/cases/compiler/checkInheritedProperty.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
class Base {
|
||||
}
|
||||
|
||||
declare const BaseFactory: new() => Base & { c: string }
|
||||
|
||||
class Derived extends BaseFactory {
|
||||
a = this.b
|
||||
b = "abc"
|
||||
}
|
||||
28
tests/cases/compiler/noCrashOnMixin2.ts
Normal file
28
tests/cases/compiler/noCrashOnMixin2.ts
Normal file
@ -0,0 +1,28 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/62921
|
||||
|
||||
class Abstract {
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args?: any[]) => T;
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
return class extends Base {
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
public trigger() {
|
||||
new Concrete();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user