Skip to content

Commit 01f7f72

Browse files
Andaristsnovader
authored andcommitted
Consistently return errorType for super expressions in classes that extend null (microsoft#55506)
1 parent 95fc667 commit 01f7f72

File tree

9 files changed

+162
-4
lines changed

9 files changed

+162
-4
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12069,7 +12069,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1206912069
/**
1207012070
* The base constructor of a class can resolve to
1207112071
* * undefinedType if the class has no extends clause,
12072-
* * unknownType if an error occurred during resolution of the extends expression,
12072+
* * errorType if an error occurred during resolution of the extends expression,
1207312073
* * nullType if the extends expression is the null value,
1207412074
* * anyType if the extends expression has type any, or
1207512075
* * an object type with at least one construct signature.
@@ -28817,7 +28817,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2881728817
* Otherwise, return false
2881828818
* @param classDecl a class declaration to check if it extends null
2881928819
*/
28820-
function classDeclarationExtendsNull(classDecl: ClassDeclaration): boolean {
28820+
function classDeclarationExtendsNull(classDecl: ClassLikeDeclaration): boolean {
2882128821
const classSymbol = getSymbolOfDeclaration(classDecl);
2882228822
const classInstanceType = getDeclaredTypeOfSymbol(classSymbol) as InterfaceType;
2882328823
const baseConstructorType = getBaseConstructorTypeOfClass(classInstanceType);
@@ -29227,6 +29227,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2922729227
return errorType;
2922829228
}
2922929229

29230+
if (classDeclarationExtendsNull(classLikeDeclaration)) {
29231+
return isCallExpression ? errorType : nullWideningType;
29232+
}
29233+
2923029234
const classType = getDeclaredTypeOfSymbol(getSymbolOfDeclaration(classLikeDeclaration)) as InterfaceType;
2923129235
const baseClassType = classType && getBaseTypes(classType)[0];
2923229236
if (!baseClassType) {
@@ -39277,7 +39281,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3927739281
// TS 1.0 spec (April 2014): 8.3.2
3927839282
// Constructors of classes with no extends clause may not contain super calls, whereas
3927939283
// constructors of derived classes must contain at least one super call somewhere in their function body.
39280-
const containingClassDecl = node.parent as ClassDeclaration;
39284+
const containingClassDecl = node.parent;
3928139285
if (getClassExtendsHeritageElement(containingClassDecl)) {
3928239286
captureLexicalThis(node.parent, containingClassDecl);
3928339287
const classExtendsNull = classDeclarationExtendsNull(containingClassDecl);
@@ -39293,7 +39297,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3929339297
// or the containing class declares instance member variables with initializers.
3929439298

3929539299
const superCallShouldBeRootLevel = !emitStandardClassFields &&
39296-
(some((node.parent as ClassDeclaration).members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) ||
39300+
(some(node.parent.members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) ||
3929739301
some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier)));
3929839302

3929939303
if (superCallShouldBeRootLevel) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
classExtendsNull2.ts(5,7): error TS2417: Class static side 'typeof C' incorrectly extends base class static side 'null'.
2+
classExtendsNull2.ts(7,5): error TS17005: A constructor cannot contain a 'super' call when its class extends 'null'.
3+
4+
5+
==== classExtendsNull2.ts (2 errors) ====
6+
// https://github.com/microsoft/TypeScript/issues/55499
7+
8+
interface Base {}
9+
10+
class C extends null {
11+
~
12+
!!! error TS2417: Class static side 'typeof C' incorrectly extends base class static side 'null'.
13+
constructor() {
14+
super();
15+
~~~~~~~
16+
!!! error TS17005: A constructor cannot contain a 'super' call when its class extends 'null'.
17+
}
18+
}
19+
interface C extends Base {}
20+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [tests/cases/compiler/classExtendsNull2.ts] ////
2+
3+
=== classExtendsNull2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/55499
5+
6+
interface Base {}
7+
>Base : Symbol(Base, Decl(classExtendsNull2.ts, 0, 0))
8+
9+
class C extends null {
10+
>C : Symbol(C, Decl(classExtendsNull2.ts, 2, 17), Decl(classExtendsNull2.ts, 8, 1))
11+
12+
constructor() {
13+
super();
14+
}
15+
}
16+
interface C extends Base {}
17+
>C : Symbol(C, Decl(classExtendsNull2.ts, 2, 17), Decl(classExtendsNull2.ts, 8, 1))
18+
>Base : Symbol(Base, Decl(classExtendsNull2.ts, 0, 0))
19+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//// [tests/cases/compiler/classExtendsNull2.ts] ////
2+
3+
=== classExtendsNull2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/55499
5+
6+
interface Base {}
7+
8+
class C extends null {
9+
>C : C
10+
11+
constructor() {
12+
super();
13+
>super() : void
14+
>super : any
15+
}
16+
}
17+
interface C extends Base {}
18+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
classExtendsNull3.ts(3,5): error TS2531: Object is possibly 'null'.
2+
classExtendsNull3.ts(9,5): error TS2531: Object is possibly 'null'.
3+
4+
5+
==== classExtendsNull3.ts (2 errors) ====
6+
class C1 extends null {
7+
static method() {
8+
super.oops;
9+
~~~~~
10+
!!! error TS2531: Object is possibly 'null'.
11+
}
12+
}
13+
14+
class C2 extends null {
15+
method() {
16+
super.oops;
17+
~~~~~
18+
!!! error TS2531: Object is possibly 'null'.
19+
}
20+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/compiler/classExtendsNull3.ts] ////
2+
3+
=== classExtendsNull3.ts ===
4+
class C1 extends null {
5+
>C1 : Symbol(C1, Decl(classExtendsNull3.ts, 0, 0))
6+
7+
static method() {
8+
>method : Symbol(C1.method, Decl(classExtendsNull3.ts, 0, 23))
9+
10+
super.oops;
11+
}
12+
}
13+
14+
class C2 extends null {
15+
>C2 : Symbol(C2, Decl(classExtendsNull3.ts, 4, 1))
16+
17+
method() {
18+
>method : Symbol(C2.method, Decl(classExtendsNull3.ts, 6, 23))
19+
20+
super.oops;
21+
}
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [tests/cases/compiler/classExtendsNull3.ts] ////
2+
3+
=== classExtendsNull3.ts ===
4+
class C1 extends null {
5+
>C1 : C1
6+
7+
static method() {
8+
>method : () => void
9+
10+
super.oops;
11+
>super.oops : any
12+
>super : null
13+
>oops : any
14+
}
15+
}
16+
17+
class C2 extends null {
18+
>C2 : C2
19+
20+
method() {
21+
>method : () => void
22+
23+
super.oops;
24+
>super.oops : any
25+
>super : null
26+
>oops : any
27+
}
28+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/55499
5+
6+
interface Base {}
7+
8+
class C extends null {
9+
constructor() {
10+
super();
11+
}
12+
}
13+
interface C extends Base {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
class C1 extends null {
5+
static method() {
6+
super.oops;
7+
}
8+
}
9+
10+
class C2 extends null {
11+
method() {
12+
super.oops;
13+
}
14+
}

0 commit comments

Comments
 (0)