diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2993ec3aa0c17..3e00af2832ccb 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -189,7 +189,7 @@ namespace ts { } if (node.name.kind === SyntaxKind.ComputedPropertyName) { const nameExpression = (node.name).expression; - // treat computed property names where expression is string/numeric literal as just string/numeric literal + // treat computed property names where expression is string/numeric literal as just string/numeric literal if (isStringOrNumericLiteral(nameExpression.kind)) { return (nameExpression).text; } @@ -450,7 +450,7 @@ namespace ts { /** * Returns true if node and its subnodes were successfully traversed. - * Returning false means that node was not examined and caller needs to dive into the node himself. + * Returning false means that node was not examined and caller needs to dive into the node himself. */ function bindReachableStatement(node: Node): void { if (checkUnreachable(node)) { @@ -560,7 +560,7 @@ namespace ts { } function bindIfStatement(n: IfStatement): void { - // denotes reachability state when entering 'thenStatement' part of the if statement: + // denotes reachability state when entering 'thenStatement' part of the if statement: // i.e. if condition is false then thenStatement is unreachable const ifTrueState = n.expression.kind === SyntaxKind.FalseKeyword ? Reachability.Unreachable : currentReachabilityState; // denotes reachability state when entering 'elseStatement': @@ -1179,7 +1179,7 @@ namespace ts { return checkStrictModePrefixUnaryExpression(node); case SyntaxKind.WithStatement: return checkStrictModeWithStatement(node); - case SyntaxKind.ThisKeyword: + case SyntaxKind.ThisType: seenThisKeyword = true; return; @@ -1528,7 +1528,7 @@ namespace ts { // unreachable code is reported if // - user has explicitly asked about it AND - // - statement is in not ambient context (statements in ambient context is already an error + // - statement is in not ambient context (statements in ambient context is already an error // so we should not report extras) AND // - node is not variable statement OR // - node is block scoped variable statement OR diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d9f5474e2ff8d..2218d53ee34d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4541,7 +4541,7 @@ namespace ts { return esSymbolType; case SyntaxKind.VoidKeyword: return voidType; - case SyntaxKind.ThisKeyword: + case SyntaxKind.ThisType: return getTypeFromThisTypeNode(node); case SyntaxKind.StringLiteral: return getTypeFromStringLiteral(node); @@ -10157,7 +10157,7 @@ namespace ts { checkDestructuringAssignment(p, type); } else { - // non-shorthand property assignments should always have initializers + // non-shorthand property assignments should always have initializers checkDestructuringAssignment((p).initializer, type); } } @@ -14620,6 +14620,9 @@ namespace ts { const type = isExpression(node) ? checkExpression(node) : getTypeFromTypeNode(node); return type.symbol; + case SyntaxKind.ThisType: + return getTypeFromTypeNode(node).symbol; + case SyntaxKind.ConstructorKeyword: // constructor keyword for an overload, should take us to the definition if it exist const constructorDeclaration = node.parent; diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 669cbcbcf0cde..59f89226d5fad 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -378,7 +378,7 @@ namespace ts { case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.VoidKeyword: - case SyntaxKind.ThisKeyword: + case SyntaxKind.ThisType: case SyntaxKind.StringLiteral: return writeTextOfNode(currentText, type); case SyntaxKind.ExpressionWithTypeArguments: diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d0314649b8884..d9ca067e6ce12 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -428,7 +428,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi * var loop = function(x) { } * var arguments_1 = arguments * for (var x;;) loop(x); - * otherwise semantics of the code will be different since 'arguments' inside converted loop body + * otherwise semantics of the code will be different since 'arguments' inside converted loop body * will refer to function that holds converted loop. * This value is set on demand. */ @@ -436,10 +436,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /* * list of non-block scoped variable declarations that appear inside converted loop - * such variable declarations should be moved outside the loop body + * such variable declarations should be moved outside the loop body * for (let x;;) { * var y = 1; - * ... + * ... * } * should be converted to * var loop = function(x) { @@ -3226,7 +3226,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } if (convertedLoopState && (getCombinedNodeFlags(decl) & NodeFlags.BlockScoped) === 0) { - // we are inside a converted loop - this can only happen in downlevel scenarios + // we are inside a converted loop - this can only happen in downlevel scenarios // record names for all variable declarations for (const varDecl of decl.declarations) { hoistVariableDeclarationFromLoop(convertedLoopState, varDecl); @@ -3551,7 +3551,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(`case "${labelMarker}": `); // if there are no outer converted loop or outer label in question is located inside outer converted loop // then emit labeled break\continue - // otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do + // otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do if (!outerLoop || (outerLoop.labels && outerLoop.labels[labelText])) { if (isBreak) { write("break "); @@ -6006,6 +6006,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: case SyntaxKind.AnyKeyword: + case SyntaxKind.ThisType: break; default: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 96c8e19e7bcc2..c2074ba22f07d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1956,6 +1956,12 @@ namespace ts { return finishNode(node); } + function parseThisTypeNode(): TypeNode { + const node = createNode(SyntaxKind.ThisType); + nextToken(); + return finishNode(node); + } + function parseTypeQuery(): TypeQueryNode { const node = createNode(SyntaxKind.TypeQuery); parseExpected(SyntaxKind.TypeOfKeyword); @@ -2388,8 +2394,9 @@ namespace ts { case SyntaxKind.StringLiteral: return parseLiteralNode(/*internName*/ true); case SyntaxKind.VoidKeyword: - case SyntaxKind.ThisKeyword: return parseTokenNode(); + case SyntaxKind.ThisKeyword: + return parseThisTypeNode(); case SyntaxKind.TypeOfKeyword: return parseTypeQuery(); case SyntaxKind.OpenBraceToken: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index eb3322e60b9fd..457a3e5ca92cb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -204,6 +204,7 @@ namespace ts { UnionType, IntersectionType, ParenthesizedType, + ThisType, // Binding patterns ObjectBindingPattern, ArrayBindingPattern, @@ -349,7 +350,7 @@ namespace ts { FirstFutureReservedWord = ImplementsKeyword, LastFutureReservedWord = YieldKeyword, FirstTypeNode = TypePredicate, - LastTypeNode = ParenthesizedType, + LastTypeNode = ThisType, FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken, FirstToken = Unknown, @@ -726,6 +727,7 @@ namespace ts { // @kind(SyntaxKind.StringKeyword) // @kind(SyntaxKind.SymbolKeyword) // @kind(SyntaxKind.VoidKeyword) + // @kind(SyntaxKind.ThisType) export interface TypeNode extends Node { _typeNodeBrand: any; } @@ -1075,7 +1077,6 @@ namespace ts { export interface DebuggerStatement extends Statement { } // @kind(SyntaxKind.MissingDeclaration) - // @factoryhidden("name", true) export interface MissingDeclaration extends DeclarationStatement, ClassElement, ObjectLiteralElement, TypeElement { name?: Identifier; } @@ -1232,7 +1233,6 @@ namespace ts { export interface TypeElement extends Declaration { _typeElementBrand: any; name?: PropertyName; - // @factoryparam questionToken?: Node; } diff --git a/src/services/services.ts b/src/services/services.ts index 9fb2eef215234..bf5652e5541f5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2314,7 +2314,7 @@ namespace ts { return true; } - + return false; } @@ -2333,7 +2333,7 @@ namespace ts { } return false; } - + function tryConsumeDefine(): boolean { let token = scanner.getToken(); if (token === SyntaxKind.Identifier && scanner.getTokenValue() === "define") { @@ -2359,7 +2359,7 @@ namespace ts { if (token !== SyntaxKind.OpenBracketToken) { return true; } - + // skip open bracket token = scanner.scan(); let i = 0; @@ -2374,7 +2374,7 @@ namespace ts { token = scanner.scan(); } return true; - + } return false; } @@ -3976,7 +3976,7 @@ namespace ts { let sourceFile = getValidSourceFile(fileName); let entries: CompletionEntry[] = []; - + if (isRightOfDot && isSourceFileJavaScript(sourceFile)) { const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries); addRange(entries, getJavaScriptCompletionEntries(sourceFile, uniqueNames)); @@ -4595,6 +4595,7 @@ namespace ts { case SyntaxKind.PropertyAccessExpression: case SyntaxKind.QualifiedName: case SyntaxKind.ThisKeyword: + case SyntaxKind.ThisType: case SyntaxKind.SuperKeyword: // For the identifiers/this/super etc get the type at position let type = typeChecker.getTypeAtLocation(node); @@ -4866,6 +4867,7 @@ namespace ts { function getSemanticDocumentHighlights(node: Node): DocumentHighlights[] { if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || + node.kind === SyntaxKind.ThisType || node.kind === SyntaxKind.SuperKeyword || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { @@ -5561,7 +5563,7 @@ namespace ts { } } - if (node.kind === SyntaxKind.ThisKeyword) { + if (node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.ThisType) { return getReferencesForThisKeyword(node, sourceFiles); } @@ -6043,7 +6045,7 @@ namespace ts { cancellationToken.throwIfCancellationRequested(); let node = getTouchingWord(sourceFile, position); - if (!node || node.kind !== SyntaxKind.ThisKeyword) { + if (!node || (node.kind !== SyntaxKind.ThisKeyword && node.kind !== SyntaxKind.ThisType)) { return; } @@ -6405,7 +6407,8 @@ namespace ts { return node.parent.kind === SyntaxKind.TypeReference || (node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(node.parent)) || - node.kind === SyntaxKind.ThisKeyword && !isExpression(node); + (node.kind === SyntaxKind.ThisKeyword && !isExpression(node)) || + node.kind === SyntaxKind.ThisType; } function isNamespaceReference(node: Node): boolean { @@ -6525,6 +6528,7 @@ namespace ts { case SyntaxKind.NullKeyword: case SyntaxKind.SuperKeyword: case SyntaxKind.ThisKeyword: + case SyntaxKind.ThisType: case SyntaxKind.Identifier: break; diff --git a/tests/baselines/reference/decoratorMetadata.js b/tests/baselines/reference/decoratorMetadata.js index 3c4637d9dab7e..35d19ae6fe97f 100644 --- a/tests/baselines/reference/decoratorMetadata.js +++ b/tests/baselines/reference/decoratorMetadata.js @@ -12,6 +12,10 @@ declare var decorator: any; class MyComponent { constructor(public Service: Service) { } + + @decorator + method(x: this) { + } } //// [service.js] @@ -37,6 +41,14 @@ var MyComponent = (function () { function MyComponent(Service) { this.Service = Service; } + MyComponent.prototype.method = function (x) { + }; + __decorate([ + decorator, + __metadata('design:type', Function), + __metadata('design:paramtypes', [Object]), + __metadata('design:returntype', void 0) + ], MyComponent.prototype, "method", null); MyComponent = __decorate([ decorator, __metadata('design:paramtypes', [service_1.default]) diff --git a/tests/baselines/reference/decoratorMetadata.symbols b/tests/baselines/reference/decoratorMetadata.symbols index 706f5ace8a921..842982286d48f 100644 --- a/tests/baselines/reference/decoratorMetadata.symbols +++ b/tests/baselines/reference/decoratorMetadata.symbols @@ -19,4 +19,12 @@ class MyComponent { >Service : Symbol(Service, Decl(component.ts, 6, 16)) >Service : Symbol(Service, Decl(component.ts, 0, 6)) } + + @decorator +>decorator : Symbol(decorator, Decl(component.ts, 2, 11)) + + method(x: this) { +>method : Symbol(method, Decl(component.ts, 7, 5)) +>x : Symbol(x, Decl(component.ts, 10, 11)) + } } diff --git a/tests/baselines/reference/decoratorMetadata.types b/tests/baselines/reference/decoratorMetadata.types index b0ce80fb1e40f..a25f55f01b101 100644 --- a/tests/baselines/reference/decoratorMetadata.types +++ b/tests/baselines/reference/decoratorMetadata.types @@ -19,4 +19,12 @@ class MyComponent { >Service : Service >Service : Service } + + @decorator +>decorator : any + + method(x: this) { +>method : (x: this) => void +>x : this + } } diff --git a/tests/baselines/reference/thisTypeInClasses.symbols b/tests/baselines/reference/thisTypeInClasses.symbols index 0915d6e5e6ba9..5ae45b923afdb 100644 --- a/tests/baselines/reference/thisTypeInClasses.symbols +++ b/tests/baselines/reference/thisTypeInClasses.symbols @@ -92,7 +92,6 @@ class C5 { let f1 = (x: this): this => this; >f1 : Symbol(f1, Decl(thisTypeInClasses.ts, 34, 11)) >x : Symbol(x, Decl(thisTypeInClasses.ts, 34, 18)) ->this : Symbol(C5, Decl(thisTypeInClasses.ts, 30, 1)) >this : Symbol(C5, Decl(thisTypeInClasses.ts, 30, 1)) let f2 = (x: this) => this; diff --git a/tests/baselines/reference/thisTypeInClasses.types b/tests/baselines/reference/thisTypeInClasses.types index 512359decd9d5..69d0f0b1f8f69 100644 --- a/tests/baselines/reference/thisTypeInClasses.types +++ b/tests/baselines/reference/thisTypeInClasses.types @@ -93,7 +93,6 @@ class C5 { >f1 : (x: this) => this >(x: this): this => this : (x: this) => this >x : this ->this : this >this : this let f2 = (x: this) => this; diff --git a/tests/cases/conformance/decorators/decoratorMetadata.ts b/tests/cases/conformance/decorators/decoratorMetadata.ts index 3f62290930946..6d7792bb832db 100644 --- a/tests/cases/conformance/decorators/decoratorMetadata.ts +++ b/tests/cases/conformance/decorators/decoratorMetadata.ts @@ -14,4 +14,8 @@ declare var decorator: any; class MyComponent { constructor(public Service: Service) { } + + @decorator + method(x: this) { + } } \ No newline at end of file