10000 Polymorphic 'this' type by ahejlsberg · Pull Request #4910 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content

Polymorphic 'this' type #4910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Sep 30, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9438a4b
Polymorphic "this" type
ahejlsberg Sep 21, 2015
89ea067
Accepting new baselines
ahejlsberg Sep 21, 2015
06a250e
Commenting out broken fourslash tests
ahejlsberg Sep 21, 2015
285483d
Merge branch 'master' into polymorphicThisType
ahejlsberg Sep 22, 2015
7acb9dd
Adding comments and addressing CR feedback
ahejlsberg Sep 22, 2015
8fd2d7a
Properly emit "this" type in declaration files
ahejlsberg Sep 25, 2015
9dee875
Add additional "this" containers
ahejlsberg Sep 25, 2015
d79f5a6
Removing a few "this" containers
ahejlsberg Sep 25, 2015
41f8aad
Write "this" as "any" when "this" reference would be an error
ahejlsberg Sep 25, 2015
31eebbf
Rewrite inaccessible "this" to containing class/interface in declarat…
ahejlsberg Sep 25, 2015
f17875e
Properly classify "this" and "await" in isExpression
ahejlsberg Sep 26, 2015
9594835
Accepting new baselines
ahejlsberg Sep 26, 2015
47c9190
Proper handling of "this" in getSymbolAtLocation
ahejlsberg Sep 26, 2015
abd2a85
Adding tests
ahejlsberg Sep 26, 2015
29f6036
Fixing comment and error message per CR feedback
ahejlsberg Sep 26, 2015
19319b2
Adding test for declaration files
ahejlsberg Sep 26, 2015
5dc8402
Make tuple type itself the 'this' type of base array type
ahejlsberg Sep 27, 2015
1c9fae8
Add tuple type test
ahejlsberg Sep 27, 2015
24f906a
Error when emitted type in declaration file references inaccessible '…
ahejlsberg Sep 29, 2015
81934ab
Accepting new baselines
ahejlsberg Sep 29, 2015
82c010e
Adding contextual typing test
ahejlsberg Sep 29, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Polymorphic "this" type
  • Loading branch information
ahejlsberg committed Sep 21, 2015
commit 9438a4bce0375e30eaf2a01bb1d73536d8cd36e1
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);
}

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.": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A 'this' type annotation is only allowed in a non-static member of a class or interface.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this isn't about type annotations, this is about references to the this type (which might or might not occur in type annotations, for example the reference could be in a type assertion).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Le 8000 arn more.

Then perhaps just make it A 'this' type is only allowed... because that follows the intended naming conventions.

"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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify that this flag only applies to interfaces


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