Skip to content

Commit 3bb2c57

Browse files
committed
Fix #3810: Handel expressions in extends clauses
1 parent c98c763 commit 3bb2c57

10 files changed

+331
-0
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16244,6 +16244,15 @@ namespace ts {
1624416244
getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
1624516245
}
1624616246

16247+
function writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) {
16248+
const classType = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node));
16249+
resolveBaseTypesOfClass(classType);
16250+
const baseType = classType.resolvedBaseTypes[0];
16251+
if (baseType) {
16252+
getSymbolDisplayBuilder().buildTypeDisplay(baseType, writer, enclosingDeclaration, flags);
16253+
}
16254+
}
16255+
1624716256
function hasGlobalName(name: string): boolean {
1624816257
return hasProperty(globals, name);
1624916258
}
@@ -16276,6 +16285,7 @@ namespace ts {
1627616285
writeTypeOfDeclaration,
1627716286
writeReturnTypeOfSignatureDeclaration,
1627816287
writeTypeOfExpression,
16288+
writeBaseConstructorTypeOfClass,
1627916289
isSymbolAccessible,
1628016290
isEntityNameVisible,
1628116291
getConstantValue,

src/compiler/declarationEmitter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,10 @@ namespace ts {
987987
else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) {
988988
write("null");
989989
}
990+
else {
991+
writer.getSymbolAccessibilityDiagnostic = getHeritageClauseVisibilityError;
992+
resolver.writeBaseConstructorTypeOfClass(<ClassLikeDeclaration>enclosingDeclaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
993+
}
990994

991995
function getHeritageClauseVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
992996
let diagnosticMessage: DiagnosticMessage;

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,7 @@ namespace ts {
18891889
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
18901890
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
18911891
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
1892+
writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
18921893
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult;
18931894
isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult;
18941895
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [declarationEmit_expressionInExtends2.ts]
2+
3+
class C<T, U> {
4+
x: T;
5+
y: U;
6+
}
7+
8+
function getClass<T>(c: T) {
9+
return C;
10+
}
11+
12+
class MyClass extends getClass(2) <string, number> {
13+
}
14+
15+
//// [declarationEmit_expressionInExtends2.js]
16+
var __extends = (this && this.__extends) || function (d, b) {
17+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
18+
function __() { this.constructor = d; }
19+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
20+
};
21+
var C = (function () {
22+
function C() {
23+
}
24+
return C;
25+
}());
26+
function getClass(c) {
27+
return C;
28+
}
29+
var MyClass = (function (_super) {
30+
__extends(MyClass, _super);
31+
function MyClass() {
32+
_super.apply(this, arguments);
33+
}
34+
return MyClass;
35+
}(getClass(2)));
36+
37+
38+
//// [declarationEmit_expressionInExtends2.d.ts]
39+
declare class C<T, U> {
40+
x: T;
41+
y: U;
42+
}
43+
declare function getClass<T>(c: T): typeof C;
44+
declare class MyClass extends C<string, number> {
45+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== tests/cases/compiler/declarationEmit_expressionInExtends2.ts ===
2+
3+
class C<T, U> {
4+
>C : Symbol(C, Decl(declarationEmit_expressionInExtends2.ts, 0, 0))
5+
>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 1, 8))
6+
>U : Symbol(U, Decl(declarationEmit_expressionInExtends2.ts, 1, 10))
7+
8+
x: T;
9+
>x : Symbol(x, Decl(declarationEmit_expressionInExtends2.ts, 1, 15))
10+
>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 1, 8))
11+
12+
y: U;
13+
>y : Symbol(y, Decl(declarationEmit_expressionInExtends2.ts, 2, 9))
14+
>U : Symbol(U, Decl(declarationEmit_expressionInExtends2.ts, 1, 10))
15+
}
16+
17+
function getClass<T>(c: T) {
18+
>getClass : Symbol(getClass, Decl(declarationEmit_expressionInExtends2.ts, 4, 1))
19+
>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 6, 18))
20+
>c : Symbol(c, Decl(declarationEmit_expressionInExtends2.ts, 6, 21))
21+
>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 6, 18))
22+
23+
return C;
24+
>C : Symbol(C, Decl(declarationEmit_expressionInExtends2.ts, 0, 0))
25+
}
26+
27+
class MyClass extends getClass(2) <string, number> {
28+
>MyClass : Symbol(MyClass, Decl(declarationEmit_expressionInExtends2.ts, 8, 1))
29+
>getClass : Symbol(getClass, Decl(declarationEmit_expressionInExtends2.ts, 4, 1))
30+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/compiler/declarationEmit_expressionInExtends2.ts ===
2+
3+
class C<T, U> {
4+
>C : C<T, U>
5+
>T : T
6+
>U : U
7+
8+
x: T;
9+
>x : T
10+
>T : T
11+
12+
y: U;
13+
>y : U
14+
>U : U
15+
}
16+
17+
function getClass<T>(c: T) {
18+
>getClass : <T>(c: T) => typeof C
19+
>T : T
20+
>c : T
21+
>T : T
22+
23+
return C;
24+
>C : typeof C
25+
}
26+
27+
class MyClass extends getClass(2) <string, number> {
28+
>MyClass : MyClass
29+
>getClass(2) : C<string, number>
30+
>getClass : <T>(c: T) => typeof C
31+
>2 : number
32+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
tests/cases/compiler/declarationEmit_expressionInExtends3.ts(29,30): error TS4020: Extends clause of exported class 'MyClass' has or is using private name 'LocalClass'.
2+
tests/cases/compiler/declarationEmit_expressionInExtends3.ts(37,31): error TS4020: Extends clause of exported class 'MyClass3' has or is using private name 'LocalInterface'.
3+
4+
5+
==== tests/cases/compiler/declarationEmit_expressionInExtends3.ts (2 errors) ====
6+
7+
export class ExportedClass<T> {
8+
x: T;
9+
}
10+
11+
class LocalClass<T, U> {
12+
x: T;
13+
y: U;
14+
}
15+
16+
export interface ExportedInterface {
17+
x: number;
18+
}
19+
20+
interface LocalInterface {
21+
x: number;
22+
}
23+
24+
function getLocalClass<T>(c: T) {
25+
return LocalClass;
26+
}
27+
28+
function getExportedClass<T>(c: T) {
29+
return ExportedClass;
30+
}
31+
32+
33+
34+
export class MyClass extends getLocalClass<LocalInterface>(undefined)<string, number> { // error LocalClass is inaccisible
35+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36+
!!! error TS4020: Extends clause of exported class 'MyClass' has or is using private name 'LocalClass'.
37+
}
38+
39+
40+
export class MyClass2 extends getExportedClass<LocalInterface>(undefined)<string> { // OK
41+
}
42+
43+
44+
export class MyClass3 extends getExportedClass<LocalInterface>(undefined)<LocalInterface> { // Error LocalInterface is inaccisble
45+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
46+
!!! error TS4020: Extends clause of exported class 'MyClass3' has or is using private name 'LocalInterface'.
47+
}
48+
49+
50+
export class MyClass4 extends getExportedClass<LocalInterface>(undefined)<ExportedInterface> { // OK
51+
}
52+
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//// [declarationEmit_expressionInExtends3.ts]
2+
3+
export class ExportedClass<T> {
4+
x: T;
5+
}
6+
7+
class LocalClass<T, U> {
8+
x: T;
9+
y: U;
10+
}
11+
12+
export interface ExportedInterface {
13+
x: number;
14+
}
15+
16+
interface LocalInterface {
17+
x: number;
18+
}
19+
20+
function getLocalClass<T>(c: T) {
21+
return LocalClass;
22+
}
23+
24+
function getExportedClass<T>(c: T) {
25+
return ExportedClass;
26+
}
27+
28+
29+
30+
export class MyClass extends getLocalClass<LocalInterface>(undefined)<string, number> { // error LocalClass is inaccisible
31+
}
32+
33+
34+
export class MyClass2 extends getExportedClass<LocalInterface>(undefined)<string> { // OK
35+
}
36+
37+
38+
export class MyClass3 extends getExportedClass<LocalInterface>(undefined)<LocalInterface> { // Error LocalInterface is inaccisble
39+
}
40+
41+
42+
export class MyClass4 extends getExportedClass<LocalInterface>(undefined)<ExportedInterface> { // OK
43+
}
44+
45+
46+
//// [declarationEmit_expressionInExtends3.js]
47+
"use strict";
48+
var __extends = (this && this.__extends) || function (d, b) {
49+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
50+
function __() { this.constructor = d; }
51+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
52+
};
53+
var ExportedClass = (function () {
54+
function ExportedClass() {
55+
}
56+
return ExportedClass;
57+
}());
58+
exports.ExportedClass = ExportedClass;
59+
var LocalClass = (function () {
60+
function LocalClass() {
61+
}
62+
return LocalClass;
63+
}());
64+
function getLocalClass(c) {
65+
return LocalClass;
66+
}
67+
function getExportedClass(c) {
68+
return ExportedClass;
69+
}
70+
var MyClass = (function (_super) {
71+
__extends(MyClass, _super);
72+
function MyClass() {
73+
_super.apply(this, arguments);
74+
}
75+
return MyClass;
76+
}(getLocalClass(undefined)));
77+
exports.MyClass = MyClass;
78+
var MyClass2 = (function (_super) {
79+
__extends(MyClass2, _super);
80+
function MyClass2() {
81+
_super.apply(this, arguments);
82+
}
83+
return MyClass2;
84+
}(getExportedClass(undefined)));
85+
exports.MyClass2 = MyClass2;
86+
var MyClass3 = (function (_super) {
87+
__extends(MyClass3, _super);
88+
function MyClass3() {
89+
_super.apply(this, arguments);
90+
}
91+
return MyClass3;
92+
}(getExportedClass(undefined)));
93+
exports.MyClass3 = MyClass3;
94+
var MyClass4 = (function (_super) {
95+
__extends(MyClass4, _super);
96+
function MyClass4() {
97+
_super.apply(this, arguments);
98+
}
99+
return MyClass4;
100+
}(getExportedClass(undefined)));
101+
exports.MyClass4 = MyClass4;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @declaration: true
2+
3+
class C<T, U> {
4+
x: T;
5+
y: U;
6+
}
7+
8+
function getClass<T>(c: T) {
9+
return C;
10+
}
11+
12+
class MyClass extends getClass(2) <string, number> {
13+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// @declaration: true
2+
3+
export class ExportedClass<T> {
4+
x: T;
5+
}
6+
7+
class LocalClass<T, U> {
8+
x: T;
9+
y: U;
10+
}
11+
12+
export interface ExportedInterface {
13+
x: number;
14+
}
15+
16+
interface LocalInterface {
17+
x: number;
18+
}
19+
20+
function getLocalClass<T>(c: T) {
21+
return LocalClass;
22+
}
23+
24+
function getExportedClass<T>(c: T) {
25+
return ExportedClass;
26+
}
27+
28+
29+
30+
export class MyClass extends getLocalClass<LocalInterface>(undefined)<string, number> { // error LocalClass is inaccisible
31+
}
32+
33+
34+
export class MyClass2 extends getExportedClass<LocalInterface>(undefined)<string> { // OK
35+
}
36+
37+
38+
export class MyClass3 extends getExportedClass<LocalInterface>(undefined)<LocalInterface> { // Error LocalInterface is inaccisble
39+
}
40+
41+
42+
export class MyClass4 extends getExportedClass<LocalInterface>(undefined)<ExportedInterface> { // OK
43+
}

0 commit comments

Comments
 (0)