Skip to content

Commit

Permalink
Polymorphic "this" type
Browse files Browse the repository at this point in the history
  • Loading branch information
ahejlsberg committed Sep 21, 2015
1 parent c9170b8 commit 9438a4b
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 91 deletions.
13 changes: 12 additions & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ namespace ts {
let container: Node;
let blockScopeContainer: Node;
let lastContainer: Node;
let seenThisKeyword: boolean;

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

forEachChild(node, bind);
if (node.kind === SyntaxKind.InterfaceDeclaration) {
seenThisKeyword = false;
forEachChild(node, bind);
node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
}
else {
forEachChild(node, bind);
}

This comment has been minimized.

Copy link
@ahejlsberg

ahejlsberg Sep 22, 2015

Author Member

No, this can't be moved to the parser because incremental parsing can't easily maintain the correct states.

container = saveContainer;
parent = saveParent;
Expand Down Expand Up @@ -851,6 +859,9 @@ namespace ts {
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
case SyntaxKind.WithStatement:
return checkStrictModeWithStatement(<WithStatement>node);
case SyntaxKind.ThisKeyword:
seenThisKeyword = true;
return;

case SyntaxKind.TypeParameter:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
Expand Down
324 changes: 241 additions & 83 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ namespace ts {
yield_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2523, category: DiagnosticCategory.Error, key: "'yield' expressions cannot be used in a parameter initializer." },
await_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2524, category: DiagnosticCategory.Error, key: "'await' expressions cannot be used in a parameter initializer." },
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." },
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." },
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." },
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." },
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." },
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,10 @@
"category": "Error",
"code": 2525
},
"'this' type is available only in a non-static member of a class or interface.": {
"category": "Error",
"code": 2526
},
"JSX element attributes type '{0}' must be an object type.": {
"category": "Error",
"code": 2600
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,7 @@ namespace ts {
let node = tryParse(parseKeywordAndNoDot);
return node || parseTypeReferenceOrTypePredicate();
case SyntaxKind.VoidKeyword:
case SyntaxKind.ThisKeyword:
return parseTokenNode<TypeNode>();
case SyntaxKind.TypeOfKeyword:
return parseTypeQuery();
Expand All @@ -2382,6 +2383,7 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.OpenBraceToken:
case SyntaxKind.OpenBracketToken:
Expand Down
14 changes: 12 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ namespace ts {
OctalLiteral = 0x00010000, // Octal numeric literal
Namespace = 0x00020000, // Namespace declaration
ExportContext = 0x00040000, // Export context (initialized by binding)
ContainsThis = 0x00080000, // Contains reference to "this"

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

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

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

// Generic class and interface types
Expand Down
7 changes: 3 additions & 4 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,13 +467,12 @@ namespace ts {
else if (node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).name === node) {
node = node.parent;
}
// fall through
case SyntaxKind.QualifiedName:
case SyntaxKind.PropertyAccessExpression:
// At this point, node is either a qualified name or an identifier
Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression,
"'node' was expected to be a qualified name, identifier or property access in 'isTypeNode'.");

case SyntaxKind.QualifiedName:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ThisKeyword:
let parent = node.parent;
if (parent.kind === SyntaxKind.TypeQuery) {
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ namespace ts {
}
getBaseTypes(): ObjectType[] {
return this.flags & (TypeFlags.Class | TypeFlags.Interface)
? this.checker.getBaseTypes(<TypeObject & InterfaceType>this)
? this.checker.getBaseTypes(<InterfaceType><Type>this)
: undefined;
}
}
Expand Down

0 comments on commit 9438a4b

Please sign in to comment.