Skip to content

Commit 247d582

Browse files
committed
Merge pull request microsoft#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

Lines changed: 184 additions & 124 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 5 additions & 0 deletions
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

Lines changed: 20 additions & 0 deletions
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

Lines changed: 2 additions & 4 deletions
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

Lines changed: 10 additions & 3 deletions
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

Lines changed: 4 additions & 1 deletion
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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
}

0 commit comments

Comments
 (0)