Skip to content

Commit 247d582

Browse files
committed
Merge pull request #3516 from Microsoft/extendsExpressions
Allow expressions in class extends clauses
2 parents 33b0a56 + 5b9a1b5 commit 247d582

File tree

132 files changed

+1348
-550
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+1348
-550
lines changed

src/compiler/checker.ts

+184-124
Large diffs are not rendered by default.

src/compiler/diagnosticInformationMap.generated.ts

+5
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,11 @@ namespace ts {
384384
Cannot_find_namespace_0: { code: 2503, category: DiagnosticCategory.Error, key: "Cannot find namespace '{0}'." },
385385
No_best_common_type_exists_among_yield_expressions: { code: 2504, category: DiagnosticCategory.Error, key: "No best common type exists among yield expressions." },
386386
A_generator_cannot_have_a_void_type_annotation: { code: 2505, category: DiagnosticCategory.Error, key: "A generator cannot have a 'void' type annotation." },
387+
_0_is_referenced_directly_or_indirectly_in_its_own_base_expression: { code: 2506, category: DiagnosticCategory.Error, key: "'{0}' is referenced directly or indirectly in its own base expression." },
388+
Type_0_is_not_a_constructor_function_type: { code: 2507, category: DiagnosticCategory.Error, key: "Type '{0}' is not a constructor function type." },
389+
No_base_constructor_has_the_specified_number_of_type_arguments: { code: 2508, category: DiagnosticCategory.Error, key: "No base constructor has the specified number of type arguments." },
390+
Base_constructor_return_type_0_is_not_a_class_or_interface_type: { code: 2509, category: DiagnosticCategory.Error, key: "Base constructor return type '{0}' is not a class or interface type." },
391+
Base_constructors_must_all_have_the_same_return_type: { code: 2510, category: DiagnosticCategory.Error, key: "Base constructors must all have the same return type." },
387392
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
388393
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
389394
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

+20
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,26 @@
15251525
"category": "Error",
15261526
"code": 2505
15271527
},
1528+
"'{0}' is referenced directly or indirectly in its own base expression.": {
1529+
"category": "Error",
1530+
"code": 2506
1531+
},
1532+
"Type '{0}' is not a constructor function type.": {
1533+
"category": "Error",
1534+
"code": 2507
1535+
},
1536+
"No base constructor has the specified number of type arguments.": {
1537+
"category": "Error",
1538+
"code": 2508
1539+
},
1540+
"Base constructor return type '{0}' is not a class or interface type.": {
1541+
"category": "Error",
1542+
"code": 2509
1543+
},
1544+
"Base constructors must all have the same return type.": {
1545+
"category": "Error",
1546+
"code": 2510
1547+
},
15281548

15291549
"Import declaration '{0}' is using private name '{1}'.": {
15301550
"category": "Error",

src/compiler/types.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1669,10 +1669,8 @@ namespace ts {
16691669
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
16701670
outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none)
16711671
localTypeParameters: TypeParameter[]; // Local type parameters (undefined if none)
1672-
}
1673-
1674-
export interface InterfaceTypeWithBaseTypes extends InterfaceType {
1675-
baseTypes: ObjectType[];
1672+
resolvedBaseConstructorType?: Type; // Resolved base constructor type of class
1673+
resolvedBaseTypes: ObjectType[]; // Resolved base types
16761674
}
16771675

16781676
export interface InterfaceTypeWithDeclaredMembers extends InterfaceType {

src/compiler/utilities.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ namespace ts {
426426
// Specialized signatures can have string literals as their parameters' type names
427427
return node.parent.kind === SyntaxKind.Parameter;
428428
case SyntaxKind.ExpressionWithTypeArguments:
429-
return true;
429+
return !isExpressionWithTypeArgumentsInClassExtendsClause(node);
430430

431431
// Identifiers and qualified names may be type nodes, depending on their context. Climb
432432
// above them to find the lowest container
@@ -460,7 +460,7 @@ namespace ts {
460460
}
461461
switch (parent.kind) {
462462
case SyntaxKind.ExpressionWithTypeArguments:
463-
return true;
463+
return !isExpressionWithTypeArgumentsInClassExtendsClause(parent);
464464
case SyntaxKind.TypeParameter:
465465
return node === (<TypeParameterDeclaration>parent).constraint;
466466
case SyntaxKind.PropertyDeclaration:
@@ -872,7 +872,6 @@ namespace ts {
872872
while (node.parent.kind === SyntaxKind.QualifiedName) {
873873
node = node.parent;
874874
}
875-
876875
return node.parent.kind === SyntaxKind.TypeQuery;
877876
case SyntaxKind.Identifier:
878877
if (node.parent.kind === SyntaxKind.TypeQuery) {
@@ -920,6 +919,8 @@ namespace ts {
920919
return node === (<ComputedPropertyName>parent).expression;
921920
case SyntaxKind.Decorator:
922921
return true;
922+
case SyntaxKind.ExpressionWithTypeArguments:
923+
return (<ExpressionWithTypeArguments>parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent);
923924
default:
924925
if (isExpression(parent)) {
925926
return true;
@@ -1913,6 +1914,12 @@ namespace ts {
19131914
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
19141915
}
19151916

1917+
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
1918+
return node.kind === SyntaxKind.ExpressionWithTypeArguments &&
1919+
(<HeritageClause>node.parent).token === SyntaxKind.ExtendsKeyword &&
1920+
node.parent.parent.kind === SyntaxKind.ClassDeclaration;
1921+
}
1922+
19161923
// Returns false if this heritage clause element's expression contains something unsupported
19171924
// (i.e. not a name or dotted name).
19181925
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {

src/harness/typeWriter.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ class TypeWriterWalker {
4141
var lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
4242
var sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node);
4343

44-
var type = this.checker.getTypeAtLocation(node);
44+
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
45+
// var type = this.checker.getTypeAtLocation(node);
46+
var type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
47+
4548
ts.Debug.assert(type !== undefined, "type doesn't exist");
4649
var symbol = this.checker.getSymbolAtLocation(node);
4750

src/services/services.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -5811,7 +5811,8 @@ namespace ts {
58115811
node = node.parent;
58125812
}
58135813

5814-
return node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.ExpressionWithTypeArguments;
5814+
return node.parent.kind === SyntaxKind.TypeReference ||
5815+
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent));
58155816
}
58165817

58175818
function isNamespaceReference(node: Node): boolean {

tests/baselines/reference/aliasUsageInAccessorsOfClass.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ import Backbone = require("aliasUsage1_backbone");
5353

5454
export class VisualizationModel extends Backbone.Model {
5555
>VisualizationModel : VisualizationModel
56-
>Backbone.Model : any
56+
>Backbone.Model : Backbone.Model
5757
>Backbone : typeof Backbone
58-
>Model : Backbone.Model
58+
>Model : typeof Backbone.Model
5959

6060
// interesting stuff here
6161
}

tests/baselines/reference/aliasUsageInArray.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ import Backbone = require("aliasUsageInArray_backbone");
4141

4242
export class VisualizationModel extends Backbone.Model {
4343
>VisualizationModel : VisualizationModel
44-
>Backbone.Model : any
44+
>Backbone.Model : Backbone.Model
4545
>Backbone : typeof Backbone
46-
>Model : Backbone.Model
46+
>Model : typeof Backbone.Model
4747

4848
// interesting stuff here
4949
}

tests/baselines/reference/aliasUsageInFunctionExpression.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ import Backbone = require("aliasUsageInFunctionExpression_backbone");
4242

4343
export class VisualizationModel extends Backbone.Model {
4444
>VisualizationModel : VisualizationModel
45-
>Backbone.Model : any
45+
>Backbone.Model : Backbone.Model
4646
>Backbone : typeof Backbone
47-
>Model : Backbone.Model
47+
>Model : typeof Backbone.Model
4848

4949
// interesting stuff here
5050
}

tests/baselines/reference/aliasUsageInGenericFunction.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ import Backbone = require("aliasUsageInGenericFunction_backbone");
5757

5858
export class VisualizationModel extends Backbone.Model {
5959
>VisualizationModel : VisualizationModel
60-
>Backbone.Model : any
60+
>Backbone.Model : Backbone.Model
6161
>Backbone : typeof Backbone
62-
>Model : Backbone.Model
62+
>Model : typeof Backbone.Model
6363

6464
// interesting stuff here
6565
}

tests/baselines/reference/aliasUsageInIndexerOfClass.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ import Backbone = require("aliasUsageInIndexerOfClass_backbone");
5050

5151
export class VisualizationModel extends Backbone.Model {
5252
>VisualizationModel : VisualizationModel
53-
>Backbone.Model : any
53+
>Backbone.Model : Backbone.Model
5454
>Backbone : typeof Backbone
55-
>Model : Backbone.Model
55+
>Model : typeof Backbone.Model
5656

5757
// interesting stuff here
5858
}

tests/baselines/reference/aliasUsageInObjectLiteral.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ import Backbone = require("aliasUsageInObjectLiteral_backbone");
5555

5656
export class VisualizationModel extends Backbone.Model {
5757
>VisualizationModel : VisualizationModel
58-
>Backbone.Model : any
58+
>Backbone.Model : Backbone.Model
5959
>Backbone : typeof Backbone
60-
>Model : Backbone.Model
60+
>Model : typeof Backbone.Model
6161

6262
// interesting stuff here
6363
}

tests/baselines/reference/aliasUsageInOrExpression.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ import Backbone = require("aliasUsageInOrExpression_backbone");
7979

8080
export class VisualizationModel extends Backbone.Model {
8181
>VisualizationModel : VisualizationModel
82-
>Backbone.Model : any
82+
>Backbone.Model : Backbone.Model
8383
>Backbone : typeof Backbone
84-
>Model : Backbone.Model
84+
>Model : typeof Backbone.Model
8585

8686
// interesting stuff here
8787
}

tests/baselines/reference/aliasUsageInTypeArgumentOfExtendsClause.types

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class C<T extends IHasVisualizationModel> {
2525
}
2626
class D extends C<IHasVisualizationModel> {
2727
>D : D
28-
>C : C<T>
28+
>C : C<IHasVisualizationModel>
2929
>IHasVisualizationModel : IHasVisualizationModel
3030

3131
x = moduleA;
@@ -46,9 +46,9 @@ import Backbone = require("aliasUsageInTypeArgumentOfExtendsClause_backbone");
4646

4747
export class VisualizationModel extends Backbone.Model {
4848
>VisualizationModel : VisualizationModel
49-
>Backbone.Model : any
49+
>Backbone.Model : Backbone.Model
5050
>Backbone : typeof Backbone
51-
>Model : Backbone.Model
51+
>Model : typeof Backbone.Model
5252

5353
// interesting stuff here
5454
}

tests/baselines/reference/aliasUsageInVarAssignment.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ import Backbone = require("aliasUsageInVarAssignment_backbone");
3737

3838
export class VisualizationModel extends Backbone.Model {
3939
>VisualizationModel : VisualizationModel
40-
>Backbone.Model : any
40+
>Backbone.Model : Backbone.Model
4141
>Backbone : typeof Backbone
42-
>Model : Backbone.Model
42+
>Model : typeof Backbone.Model
4343

4444
// interesting stuff here
4545
}

tests/baselines/reference/arrayLiteralsWithRecursiveGenerics.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class List<T> {
1717
class DerivedList<U> extends List<U> {
1818
>DerivedList : DerivedList<U>
1919
>U : U
20-
>List : List<T>
20+
>List : List<U>
2121
>U : U
2222

2323
foo: U;

tests/baselines/reference/baseTypeWrappingInstantiationChain.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
class C<T1> extends CBase<T1> {
33
>C : C<T1>
44
>T1 : T1
5-
>CBase : CBase<T2>
5+
>CBase : CBase<T1>
66
>T1 : T1
77

88
public works() {
@@ -35,7 +35,7 @@ class C<T1> extends CBase<T1> {
3535
class CBase<T2> extends CBaseBase<Wrapper<T2>> {
3636
>CBase : CBase<T2>
3737
>T2 : T2
38-
>CBaseBase : CBaseBase<T3>
38+
>CBaseBase : CBaseBase<Wrapper<T2>>
3939
>Wrapper : Wrapper<T5>
4040
>T2 : T2
4141

tests/baselines/reference/checkForObjectTooStrict.errors.txt

-40
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
=== tests/cases/compiler/checkForObjectTooStrict.ts ===
2+
module Foo {
3+
>Foo : Symbol(Foo, Decl(checkForObjectTooStrict.ts, 0, 0))
4+
5+
export class Object {
6+
>Object : Symbol(Object, Decl(checkForObjectTooStrict.ts, 0, 12))
7+
8+
}
9+
10+
}
11+
12+
13+
14+
class Bar extends Foo.Object { // should work
15+
>Bar : Symbol(Bar, Decl(checkForObjectTooStrict.ts, 6, 1))
16+
>Foo.Object : Symbol(Foo.Object, Decl(checkForObjectTooStrict.ts, 0, 12))
17+
>Foo : Symbol(Foo, Decl(checkForObjectTooStrict.ts, 0, 0))
18+
>Object : Symbol(Foo.Object, Decl(checkForObjectTooStrict.ts, 0, 12))
19+
20+
constructor () {
21+
22+
super();
23+
>super : Symbol(Foo.Object, Decl(checkForObjectTooStrict.ts, 0, 12))
24+
25+
}
26+
27+
}
28+
29+
30+
class Baz extends Object {
31+
>Baz : Symbol(Baz, Decl(checkForObjectTooStrict.ts, 18, 1))
32+
>Object : Symbol(Object, Decl(lib.d.ts, 92, 1), Decl(lib.d.ts, 223, 11))
33+
34+
constructor () { // ERROR, as expected
35+
36+
super();
37+
>super : Symbol(ObjectConstructor, Decl(lib.d.ts, 124, 1))
38+
39+
}
40+
41+
}
42+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
=== tests/cases/compiler/checkForObjectTooStrict.ts ===
2+
module Foo {
3+
>Foo : typeof Foo
4+
5+
export class Object {
6+
>Object : Object
7+
8+
}
9+
10+
}
11+
12+
13+
14+
class Bar extends Foo.Object { // should work
15+
>Bar : Bar
16+
>Foo.Object : Foo.Object
17+
>Foo : typeof Foo
18+
>Object : typeof Foo.Object
19+
20+
constructor () {
21+
22+
super();
23+
>super() : void
24+
>super : typeof Foo.Object
25+
26+
}
27+
28+
}
29+
30+
31+
class Baz extends Object {
32+
>Baz : Baz
33+
>Object : Object
34+
35+
constructor () { // ERROR, as expected
36+
37+
super();
38+
>super() : void
39+
>super : ObjectConstructor
40+
41+
}
42+
43+
}
44+

0 commit comments

Comments
 (0)