Skip to content

Commit 9438a4b

Browse files
committed
Polymorphic "this" type
1 parent c9170b8 commit 9438a4b

8 files changed

+276
-91
lines changed

src/compiler/binder.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ namespace ts {
8888
let container: Node;
8989
let blockScopeContainer: Node;
9090
let lastContainer: Node;
91+
let seenThisKeyword: boolean;
9192

9293
// If this file is an external module, then it is automatically in strict-mode according to
9394
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
@@ -329,7 +330,14 @@ namespace ts {
329330
blockScopeContainer.locals = undefined;
330331
}
331332

332-
forEachChild(node, bind);
333+
if (node.kind === SyntaxKind.InterfaceDeclaration) {
334+
seenThisKeyword = false;
335+
forEachChild(node, bind);
336+
node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
337+
}
338+
else {
339+
forEachChild(node, bind);
340+
}
333341

334342
container = saveContainer;
335343
parent = saveParent;
@@ -851,6 +859,9 @@ namespace ts {
851859
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
852860
case SyntaxKind.WithStatement:
853861
return checkStrictModeWithStatement(<WithStatement>node);
862+
case SyntaxKind.ThisKeyword:
863+
seenThisKeyword = true;
864+
return;
854865

855866
case SyntaxKind.TypeParameter:
856867
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);

src/compiler/checker.ts

+241-83
Large diffs are not rendered by default.

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ namespace ts {
416416
yield_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2523, category: DiagnosticCategory.Error, key: "'yield' expressions cannot be used in a parameter initializer." },
417417
await_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2524, category: DiagnosticCategory.Error, key: "'await' expressions cannot be used in a parameter initializer." },
418418
Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value: { code: 2525, category: DiagnosticCategory.Error, key: "Initializer provides no value for this binding element and the binding element has no default value." },
419+
this_type_is_available_only_in_a_non_static_member_of_a_class_or_interface: { code: 2526, category: DiagnosticCategory.Error, key: "'this' type is available only in a non-static member of a class or interface." },
419420
JSX_element_attributes_type_0_must_be_an_object_type: { code: 2600, category: DiagnosticCategory.Error, key: "JSX element attributes type '{0}' must be an object type." },
420421
The_return_type_of_a_JSX_element_constructor_must_return_an_object_type: { code: 2601, category: DiagnosticCategory.Error, key: "The return type of a JSX element constructor must return an object type." },
421422
JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist: { code: 2602, category: DiagnosticCategory.Error, key: "JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist." },

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -1653,6 +1653,10 @@
16531653
"category": "Error",
16541654
"code": 2525
16551655
},
1656+
"'this' type is available only in a non-static member of a class or interface.": {
1657+
"category": "Error",
1658+
"code": 2526
1659+
},
16561660
"JSX element attributes type '{0}' must be an object type.": {
16571661
"category": "Error",
16581662
"code": 2600

src/compiler/parser.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,7 @@ namespace ts {
23602360
let node = tryParse(parseKeywordAndNoDot);
23612361
return node || parseTypeReferenceOrTypePredicate();
23622362
case SyntaxKind.VoidKeyword:
2363+
case SyntaxKind.ThisKeyword:
23632364
return parseTokenNode<TypeNode>();
23642365
case SyntaxKind.TypeOfKeyword:
23652366
return parseTypeQuery();
@@ -2382,6 +2383,7 @@ namespace ts {
23822383
case SyntaxKind.BooleanKeyword:
23832384
case SyntaxKind.SymbolKeyword:
23842385
case SyntaxKind.VoidKeyword:
2386+
case SyntaxKind.ThisKeyword:
23852387
case SyntaxKind.TypeOfKeyword:
23862388
case SyntaxKind.OpenBraceToken:
23872389
case SyntaxKind.OpenBracketToken:

src/compiler/types.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ namespace ts {
376376
OctalLiteral = 0x00010000, // Octal numeric literal
377377
Namespace = 0x00020000, // Namespace declaration
378378
ExportContext = 0x00040000, // Export context (initialized by binding)
379+
ContainsThis = 0x00080000, // Contains reference to "this"
379380

380381
Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async,
381382
AccessibilityModifier = Public | Private | Protected,
@@ -1797,6 +1798,7 @@ namespace ts {
17971798
/* @internal */
17981799
ContainsAnyFunctionType = 0x00800000, // Type is or contains object literal type
17991800
ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6
1801+
ThisType = 0x02000000, // This type
18001802

18011803
/* @internal */
18021804
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
@@ -1842,6 +1844,7 @@ namespace ts {
18421844
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
18431845
outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none)
18441846
localTypeParameters: TypeParameter[]; // Local type parameters (undefined if none)
1847+
thisType: TypeParameter; // The "this" type (undefined if none)
18451848
/* @internal */
18461849
resolvedBaseConstructorType?: Type; // Resolved base constructor type of class
18471850
/* @internal */
@@ -1856,10 +1859,17 @@ namespace ts {
18561859
declaredNumberIndexType: Type; // Declared numeric index type
18571860
}
18581861

1859-
// Type references (TypeFlags.Reference)
1862+
// Type references (TypeFlags.Reference). When a class or interface has type parameters or
1863+
// a "this" type, references to the class or interface are made using type references. The
1864+
// typeArguments property specififes the types to substitute for the type parameters of the
1865+
// class or interface and optionally includes an extra element that specifies the type to
1866+
// substitute for "this" in the resulting instantiation. When no extra argument is present,
1867+
// the type reference itself is substituted for "this". The typeArguments property is undefined
1868+
// if the class or interface has no type parameters and the reference isn't specifying an
1869+
// explicit "this" argument.
18601870
export interface TypeReference extends ObjectType {
18611871
target: GenericType; // Type reference target
1862-
typeArguments: Type[]; // Type reference type arguments
1872+
typeArguments: Type[]; // Type reference type arguments (undefined if none)
18631873
}
18641874

18651875
// Generic class and interface types

src/compiler/utilities.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -467,13 +467,12 @@ namespace ts {
467467
else if (node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).name === node) {
468468
node = node.parent;
469469
}
470-
// fall through
471-
case SyntaxKind.QualifiedName:
472-
case SyntaxKind.PropertyAccessExpression:
473470
// At this point, node is either a qualified name or an identifier
474471
Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression,
475472
"'node' was expected to be a qualified name, identifier or property access in 'isTypeNode'.");
476-
473+
case SyntaxKind.QualifiedName:
474+
case SyntaxKind.PropertyAccessExpression:
475+
case SyntaxKind.ThisKeyword:
477476
let parent = node.parent;
478477
if (parent.kind === SyntaxKind.TypeQuery) {
479478
return false;

src/services/services.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ namespace ts {
725725
}
726726
getBaseTypes(): ObjectType[] {
727727
return this.flags & (TypeFlags.Class | TypeFlags.Interface)
728-
? this.checker.getBaseTypes(<TypeObject & InterfaceType>this)
728+
? this.checker.getBaseTypes(<InterfaceType><Type>this)
729729
: undefined;
730730
}
731731
}

0 commit comments

Comments
 (0)