From af7df838253b7b8489fcd9137e8f4220786d2be5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 08:57:10 -0800 Subject: [PATCH 01/31] Parse type predicates only in return types. --- src/compiler/parser.ts | 53 +++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e4262458d30..10d4a47c3df 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -908,17 +908,19 @@ namespace ts { return result; } - // Invokes the provided callback then unconditionally restores the parser to the state it - // was in immediately prior to invoking the callback. The result of invoking the callback - // is returned from this function. + /** Invokes the provided callback then unconditionally restores the parser to the state it + * was in immediately prior to invoking the callback. The result of invoking the callback + * is returned from this function. + */ function lookAhead(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ true); } - // Invokes the provided callback. If the callback returns something falsy, then it restores - // the parser to the state it was in immediately prior to invoking the callback. If the - // callback returns something truthy, then the parser state is not rolled back. The result - // of invoking the callback is returned from this function. + /** Invokes the provided callback. If the callback returns something falsy, then it restores + * the parser to the state it was in immediately prior to invoking the callback. If the + * callback returns something truthy, then the parser state is not rolled back. The result + * of invoking the callback is returned from this function. + */ function tryParse(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ false); } @@ -1960,15 +1962,8 @@ namespace ts { // TYPES - function parseTypeReferenceOrTypePredicate(): TypeReferenceNode | TypePredicateNode { + function parseTypeReference(): TypeReferenceNode { const typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected); - if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { - nextToken(); - const node = createNode(SyntaxKind.TypePredicate, typeName.pos); - node.parameterName = typeName; - node.type = parseType(); - return finishNode(node); - } const node = createNode(SyntaxKind.TypeReference, typeName.pos); node.typeName = typeName; if (!scanner.hasPrecedingLineBreak() && token === SyntaxKind.LessThanToken) { @@ -2100,10 +2095,10 @@ namespace ts { if (returnTokenRequired) { parseExpected(returnToken); - signature.type = parseType(); + signature.type = parseTypeOrTypePredicate(); } else if (parseOptional(returnToken)) { - signature.type = parseType(); + signature.type = parseTypeOrTypePredicate(); } } @@ -2419,7 +2414,7 @@ namespace ts { case SyntaxKind.SymbolKeyword: // If these are followed by a dot, then parse these out as a dotted type reference instead. const node = tryParse(parseKeywordAndNoDot); - return node || parseTypeReferenceOrTypePredicate(); + return node || parseTypeReference(); case SyntaxKind.StringLiteral: return parseStringLiteralTypeNode(); case SyntaxKind.VoidKeyword: @@ -2435,7 +2430,7 @@ namespace ts { case SyntaxKind.OpenParenToken: return parseParenthesizedType(); default: - return parseTypeReferenceOrTypePredicate(); + return parseTypeReference(); } } @@ -2541,6 +2536,26 @@ namespace ts { } return false; } + + function parseTypeOrTypePredicate(): TypeNode { + const typePredicateVariable = tryParse(() => { + const id = parseIdentifier(); + if (token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { + nextToken(); + return id; + } + }); + const t = parseType(); + if(typePredicateVariable) { + const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); + node.parameterName = typePredicateVariable; + node.type = t; + return finishNode(node); + } + else { + return t; + } + } function parseType(): TypeNode { // The rules about 'yield' only apply to actual code/expression contexts. They don't From fd311d4e274251208c9dc795b4d071f6ffebf822 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 09:11:37 -0800 Subject: [PATCH 02/31] Fix lint --- src/compiler/parser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 10d4a47c3df..1c41003a7a1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2536,7 +2536,7 @@ namespace ts { } return false; } - + function parseTypeOrTypePredicate(): TypeNode { const typePredicateVariable = tryParse(() => { const id = parseIdentifier(); @@ -2546,7 +2546,7 @@ namespace ts { } }); const t = parseType(); - if(typePredicateVariable) { + if (typePredicateVariable) { const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); node.parameterName = typePredicateVariable; node.type = t; From 1b63040d3654585d075bb0f69fc0f5aae41fc20b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 09:13:41 -0800 Subject: [PATCH 03/31] Add tests and accept baselines --- .../reference/typeAssertions.errors.txt | 52 ++++++++++++++++++- tests/baselines/reference/typeAssertions.js | 22 ++++++++ .../typeAssertions/typeAssertions.ts | 9 ++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/typeAssertions.errors.txt b/tests/baselines/reference/typeAssertions.errors.txt index a2ad28801c8..c7401e4fcf9 100644 --- a/tests/baselines/reference/typeAssertions.errors.txt +++ b/tests/baselines/reference/typeAssertions.errors.txt @@ -7,9 +7,23 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(37,13): err Property 'q' is missing in type 'SomeDerived'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. Property 'q' is missing in type 'SomeBase'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,5): error TS2304: Cannot find name 'numOrStr'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,14): error TS1005: '>' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,14): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,17): error TS1005: ')' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,17): error TS2304: Cannot find name 'string'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,48): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(45,2): error TS2322: Type 'number | string' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,32): error TS2304: Cannot find name 'numOrStr'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,41): error TS1005: ')' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,41): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,44): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,44): error TS2304: Cannot find name 'string'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): error TS1005: ';' expected. -==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (5 errors) ==== +==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (18 errors) ==== // Function call whose argument is a 1 arg generic function call with explicit type arguments function fn1(t: T) { } function fn2(t: any) { } @@ -64,5 +78,41 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): err !!! error TS2352: Property 'q' is missing in type 'SomeBase'. someOther = someOther; + // Type assertion cannot be a type-predicate type + var numOrStr: number | string; + var str: string; + if((numOrStr === undefined)) { // Error + ~~~~~~~~ +!!! error TS2304: Cannot find name 'numOrStr'. + ~~ +!!! error TS1005: '>' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~~~~~~ +!!! error TS1005: ')' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'string'. + ~ +!!! error TS1005: ';' expected. + str = numOrStr; // Error, no narrowing occurred + ~~~ +!!! error TS2322: Type 'number | string' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + + if((numOrStr === undefined) as numOrStr is string) { // Error + ~~~~~~~~ +!!! error TS2304: Cannot find name 'numOrStr'. + ~~ +!!! error TS1005: ')' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'string'. + ~ +!!! error TS1005: ';' expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/typeAssertions.js b/tests/baselines/reference/typeAssertions.js index 3645e61f2ba..8bdd927c99e 100644 --- a/tests/baselines/reference/typeAssertions.js +++ b/tests/baselines/reference/typeAssertions.js @@ -39,6 +39,15 @@ someOther = someDerived; // Error someOther = someBase; // Error someOther = someOther; +// Type assertion cannot be a type-predicate type +var numOrStr: number | string; +var str: string; +if((numOrStr === undefined)) { // Error + str = numOrStr; // Error, no narrowing occurred +} + +if((numOrStr === undefined) as numOrStr is string) { // Error +} @@ -87,3 +96,16 @@ someDerived = someOther; // Error someOther = someDerived; // Error someOther = someBase; // Error someOther = someOther; +// Type assertion cannot be a type-predicate type +var numOrStr; +var str; +if (is) + string > (numOrStr === undefined); +{ + str = numOrStr; // Error, no narrowing occurred +} +if ((numOrStr === undefined)) + is; +string; +{ +} diff --git a/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts b/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts index 2acbbe53789..f30eafb3918 100644 --- a/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts +++ b/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts @@ -38,4 +38,13 @@ someOther = someDerived; // Error someOther = someBase; // Error someOther = someOther; +// Type assertion cannot be a type-predicate type +var numOrStr: number | string; +var str: string; +if((numOrStr === undefined)) { // Error + str = numOrStr; // Error, no narrowing occurred +} + +if((numOrStr === undefined) as numOrStr is string) { // Error +} From 47d267cdde0344ba6c0ec18cc871494fb46963bf Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 09:36:46 -0800 Subject: [PATCH 04/31] Move type predicate checking to checkTypePredicate Also remove now-unused "Type predicate is only allowed as a return type" diagnostic. --- src/compiler/checker.ts | 130 +++++++++++++-------------- src/compiler/diagnosticMessages.json | 4 - 2 files changed, 60 insertions(+), 74 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 30d4818592b..66ba4fcee90 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10985,7 +10985,61 @@ namespace ts { return -1; } - function isInLegalTypePredicatePosition(node: Node): boolean { + function checkTypePredicate(node: TypePredicateNode) { + const parent = getTypePredicateParent(node); + if (!parent) { + return; + } + const typePredicate = getSignatureFromDeclaration(parent).typePredicate; + if (typePredicate.parameterIndex >= 0) { + if (parent.parameters[typePredicate.parameterIndex].dotDotDotToken) { + error(node.parameterName, + Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); + } + else { + checkTypeAssignableTo(typePredicate.type, + getTypeOfNode(parent.parameters[typePredicate.parameterIndex]), + node.type); + } + } + else if (node.parameterName) { + let hasReportedError = false; + for (var param of parent.parameters) { + if (hasReportedError) { + break; + } + if (param.name.kind === SyntaxKind.ObjectBindingPattern || + param.name.kind === SyntaxKind.ArrayBindingPattern) { + + (function checkBindingPattern(pattern: BindingPattern) { + for (const element of pattern.elements) { + if (element.name.kind === SyntaxKind.Identifier && + (element.name).text === typePredicate.parameterName) { + + error(node.parameterName, + Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, + typePredicate.parameterName); + hasReportedError = true; + break; + } + else if (element.name.kind === SyntaxKind.ArrayBindingPattern || + element.name.kind === SyntaxKind.ObjectBindingPattern) { + + checkBindingPattern(element.name); + } + } + })(param.name); + } + } + if (!hasReportedError) { + error(node.parameterName, + Diagnostics.Cannot_find_parameter_0, + typePredicate.parameterName); + } + } + } + + function getTypePredicateParent(node: Node): SignatureDeclaration { switch (node.parent.kind) { case SyntaxKind.ArrowFunction: case SyntaxKind.CallSignature: @@ -10994,9 +11048,11 @@ namespace ts { case SyntaxKind.FunctionType: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return node === (node.parent).type; + const parent = node.parent; + if (node === parent.type) { + return parent; + } } - return false; } function checkSignatureDeclaration(node: SignatureDeclaration) { @@ -11015,67 +11071,7 @@ namespace ts { forEach(node.parameters, checkParameter); - if (node.type) { - if (node.type.kind === SyntaxKind.TypePredicate) { - const typePredicate = getSignatureFromDeclaration(node).typePredicate; - const typePredicateNode = node.type; - if (isInLegalTypePredicatePosition(typePredicateNode)) { - if (typePredicate.parameterIndex >= 0) { - if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) { - error(typePredicateNode.parameterName, - Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); - } - else { - checkTypeAssignableTo(typePredicate.type, - getTypeOfNode(node.parameters[typePredicate.parameterIndex]), - typePredicateNode.type); - } - } - else if (typePredicateNode.parameterName) { - let hasReportedError = false; - for (var param of node.parameters) { - if (hasReportedError) { - break; - } - if (param.name.kind === SyntaxKind.ObjectBindingPattern || - param.name.kind === SyntaxKind.ArrayBindingPattern) { - - (function checkBindingPattern(pattern: BindingPattern) { - for (const element of pattern.elements) { - if (element.name.kind === SyntaxKind.Identifier && - (element.name).text === typePredicate.parameterName) { - - error(typePredicateNode.parameterName, - Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, - typePredicate.parameterName); - hasReportedError = true; - break; - } - else if (element.name.kind === SyntaxKind.ArrayBindingPattern || - element.name.kind === SyntaxKind.ObjectBindingPattern) { - - checkBindingPattern(element.name); - } - } - })(param.name); - } - } - if (!hasReportedError) { - error(typePredicateNode.parameterName, - Diagnostics.Cannot_find_parameter_0, - typePredicate.parameterName); - } - } - } - else { - error(typePredicateNode, - Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); - } - } - else { - checkSourceElement(node.type); - } - } + checkSourceElement(node.type); if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); @@ -14217,12 +14213,6 @@ namespace ts { } } - function checkTypePredicate(node: TypePredicateNode) { - if (!isInLegalTypePredicatePosition(node)) { - error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); - } - } - function checkSourceElement(node: Node): void { if (!node) { return; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 331568eae22..bc5a252b304 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -711,10 +711,6 @@ "category": "Error", "code": 1227 }, - "A type predicate is only allowed in return type position for functions and methods.": { - "category": "Error", - "code": 1228 - }, "A type predicate cannot reference a rest parameter.": { "category": "Error", "code": 1229 From 3306ee8a91ff8114238d5c990468e21cd0b21257 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 09:39:25 -0800 Subject: [PATCH 05/31] Accept baselines --- .../typeGuardFunctionErrors.errors.txt | 107 +++++++++++++----- .../reference/typeGuardFunctionErrors.js | 16 ++- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 92d9d21f0cc..470ad00bcf7 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,15 +1,21 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(2,7): error TS2300: Duplicate identifier 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,60): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,62): error TS1005: ';' expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,33): error TS1225: Cannot find parameter 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(31,5): error TS1131: Property or signature expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(31,5): error TS7027: Unreachable code detected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(32,1): error TS1128: Declaration or statement expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(34,38): error TS1225: Cannot find parameter 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(38,51): error TS2322: Type 'B' is not assignable to type 'A'. Property 'propA' is missing in type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(42,56): error TS2322: Type 'number' is not assignable to type 'string'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(46,56): error TS2322: Type 'T[]' is not assignable to type 'string'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(50,1): error TS7027: Unreachable code detected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(60,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(65,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(70,7): error TS2339: Property 'propB' does not exist on type 'A'. @@ -22,27 +28,40 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(85,1): Type predicate 'p2 is A' is not assignable to 'p1 is A'. Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(91,1): error TS2322: Type '(p1: any, p2: any, p3: any) => p1 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,25): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): error TS2304: Cannot find name 'b'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,11): error TS1005: '=' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,11): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,14): error TS1005: ',' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,14): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS2304: Cannot find name 'b'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,18): error TS1005: '=' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,18): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,21): error TS1005: ',' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS2304: Cannot find name 'b'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,22): error TS1144: '{' or ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,22): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,25): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,27): error TS1005: ';' expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2322: Type 'boolean' is not assignable to type 'D'. Property 'm1' is missing in type 'Boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(111,16): error TS2408: Setters cannot return a value. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,18): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS2304: Cannot find name 'p1'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,25): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,25): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,28): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(121,1): error TS1128: Declaration or statement expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(124,20): error TS1229: A type predicate cannot reference a rest parameter. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (33 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (50 errors) ==== class A { + ~ +!!! error TS2300: Duplicate identifier 'A'. propA: number; } @@ -61,6 +80,16 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 } function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + ~ +!!! error TS2304: Cannot find name 'x'. + ~~ +!!! error TS1144: '{' or ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1005: ';' expected. return true; } @@ -82,6 +111,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 return true; ~~~~~~ !!! error TS1131: Property or signature expected. + ~~~~~~ +!!! error TS7027: Unreachable code detected. } ~ !!! error TS1128: Declaration or statement expected. @@ -112,8 +143,6 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 } let a: A; - ~~~ -!!! error TS7027: Unreachable code detected. let b: B; declare function isB(p1): p1 is B; @@ -179,22 +208,42 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 // Type predicates in non-return type positions var b1: b is A; - ~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~ +!!! error TS2304: Cannot find name 'b'. + ~~ +!!! error TS1005: '=' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ',' expected. + ~ +!!! error TS2300: Duplicate identifier 'A'. function b2(a: b is A) {}; - ~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~ +!!! error TS2304: Cannot find name 'b'. + ~~ +!!! error TS1005: '=' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ',' expected. function b3(): A | b is A { - ~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~ +!!! error TS2304: Cannot find name 'b'. + ~~ +!!! error TS1144: '{' or ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1005: ';' expected. return true; }; // Non-compatiable type predicate positions for signature declarations class D { constructor(p1: A): p1 is C { - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2322: Type 'boolean' is not assignable to type 'D'. @@ -203,13 +252,9 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } get m1(p1: A): p1 is C { - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; } set m2(p1: A): p1 is C { - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2408: Setters cannot return a value. @@ -218,15 +263,21 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 interface I1 { new (p1: A): p1 is C; - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. } interface I2 { [index: number]: p1 is C; - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~~ +!!! error TS2304: Cannot find name 'p1'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. } + ~ +!!! error TS1128: Declaration or statement expected. // Reference to rest parameter function b4(...a): a is A { diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index 4923f544345..1d1660fe924 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -171,7 +171,9 @@ var C = (function (_super) { function hasANonBooleanReturnStatement(x) { return ''; } -function hasTypeGuardTypeInsideTypeGuardType(x) { +is; +A; +{ return true; } function hasMissingIsKeyword() { @@ -224,10 +226,14 @@ assign3 = function (p1, p2, p3) { return true; }; // Type predicates in non-return type positions -var b1; -function b2(a) { } +var b1 = is, A; +function b2(a, A) { + if (a === void 0) { a = is; } +} ; -function b3() { +is; +A; +{ return true; } ; @@ -252,6 +258,8 @@ var D = (function () { }); return D; })(); +is; +C; // Reference to rest parameter function b4() { var a = []; From a4e21d78582a4aa47835f660a683bfbf49351de3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 12:52:19 -0800 Subject: [PATCH 06/31] Address comments --- src/compiler/checker.ts | 62 ++++++++++++++++++++++------------------- src/compiler/parser.ts | 6 ++-- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 66ba4fcee90..fed9c026717 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11004,37 +11004,19 @@ namespace ts { } else if (node.parameterName) { let hasReportedError = false; - for (var param of parent.parameters) { - if (hasReportedError) { - break; - } - if (param.name.kind === SyntaxKind.ObjectBindingPattern || - param.name.kind === SyntaxKind.ArrayBindingPattern) { - - (function checkBindingPattern(pattern: BindingPattern) { - for (const element of pattern.elements) { - if (element.name.kind === SyntaxKind.Identifier && - (element.name).text === typePredicate.parameterName) { - - error(node.parameterName, - Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, - typePredicate.parameterName); - hasReportedError = true; - break; - } - else if (element.name.kind === SyntaxKind.ArrayBindingPattern || - element.name.kind === SyntaxKind.ObjectBindingPattern) { - - checkBindingPattern(element.name); - } - } - })(param.name); + for (const param of parent.parameters) { + if ((param.name.kind === SyntaxKind.ObjectBindingPattern || + param.name.kind === SyntaxKind.ArrayBindingPattern) && + checkBindingPatternForTypePredicateVariable( + param.name, + node.parameterName, + typePredicate.parameterName)) { + hasReportedError = true; + break; } } if (!hasReportedError) { - error(node.parameterName, - Diagnostics.Cannot_find_parameter_0, - typePredicate.parameterName); + error(node.parameterName, Diagnostics.Cannot_find_parameter_0, typePredicate.parameterName); } } } @@ -11055,6 +11037,30 @@ namespace ts { } } + function checkBindingPatternForTypePredicateVariable( + pattern: BindingPattern, + predicateVariableNode: Node, + predicateVariableName: string) { + for (const element of pattern.elements) { + if (element.name.kind === SyntaxKind.Identifier && + (element.name).text === predicateVariableName) { + error(predicateVariableNode, + Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, + predicateVariableName); + return true; + } + else if (element.name.kind === SyntaxKind.ArrayBindingPattern || + element.name.kind === SyntaxKind.ObjectBindingPattern) { + if (checkBindingPatternForTypePredicateVariable( + element.name, + predicateVariableNode, + predicateVariableName)) { + return true; + } + } + } + } + function checkSignatureDeclaration(node: SignatureDeclaration) { // Grammar checking if (node.kind === SyntaxKind.IndexSignature) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1c41003a7a1..e146e809122 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2545,15 +2545,15 @@ namespace ts { return id; } }); - const t = parseType(); + const type = parseType(); if (typePredicateVariable) { const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); node.parameterName = typePredicateVariable; - node.type = t; + node.type = type; return finishNode(node); } else { - return t; + return type; } } From f9846ff2bc2a253a0ff900b508c3cb25164225bb Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 8 Dec 2015 14:11:46 -0800 Subject: [PATCH 07/31] Address comments --- src/compiler/parser.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e146e809122..f28f82ed401 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2538,13 +2538,11 @@ namespace ts { } function parseTypeOrTypePredicate(): TypeNode { - const typePredicateVariable = tryParse(() => { - const id = parseIdentifier(); - if (token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { - nextToken(); - return id; - } - }); + let typePredicateVariable: Identifier; + if (isIdentifier()) { + typePredicateVariable = tryParse(parseTypePredicatePrefix); + } + const type = parseType(); if (typePredicateVariable) { const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); @@ -2557,6 +2555,14 @@ namespace ts { } } + function parseTypePredicatePrefix() { + const id = parseIdentifier(); + if (token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { + nextToken(); + return id; + } + } + function parseType(): TypeNode { // The rules about 'yield' only apply to actual code/expression contexts. They don't // apply to 'type' contexts. So we disable these parameters here before moving on. From 9ab9940fd03d4eb11422a0ab49bf96df19ad2a13 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 22 Dec 2015 11:48:01 -0800 Subject: [PATCH 08/31] Remove unused error for this-type predicates. Also: 1. Remove notes I wrote myself for merging. 2. Switch to pattern matching on properties in a few places. --- src/compiler/checker.ts | 51 ++++++++-------------------- src/compiler/diagnosticMessages.json | 4 --- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 63e44bad83c..ce40f8b7348 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11138,29 +11138,19 @@ namespace ts { if (!parent) { return; } - // NEW we now get and check the return type -- is this needed? - // Because of Wesley's change, sigs no longer have a special typePred member, - // they have a type that extends PredicateType (with flags including PredicateType) const returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(parent)); if (!returnType || !(returnType.flags & TypeFlags.PredicateType)) { return; } const { parameterName } = node; if (parameterName.kind === SyntaxKind.ThisType) { - if (!isInLegalThisTypePredicatePosition(node)) { - error(node, Diagnostics.A_this_based_type_predicate_is_only_allowed_within_a_class_or_interface_s_members_get_accessors_or_return_type_positions_for_functions_and_methods); - } - else { - getTypeFromThisTypeNode(parameterName as ThisTypeNode); - // TODO: Should probably skip past the other error checking now - // ... because I bet the above function is the equivalent of this one. - } + getTypeFromThisTypeNode(parameterName as ThisTypeNode); } else { const typePredicate = (returnType).predicate; if (typePredicate.parameterIndex >= 0) { if (parent.parameters[typePredicate.parameterIndex].dotDotDotToken) { - error(node.parameterName, + error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); } else { @@ -11169,14 +11159,14 @@ namespace ts { node.type); } } - else if (node.parameterName) { + else if (parameterName) { let hasReportedError = false; - for (const param of parent.parameters) { - if ((param.name.kind === SyntaxKind.ObjectBindingPattern || - param.name.kind === SyntaxKind.ArrayBindingPattern) && + for (const { name } of parent.parameters) { + if ((name.kind === SyntaxKind.ObjectBindingPattern || + name.kind === SyntaxKind.ArrayBindingPattern) && checkBindingPatternForTypePredicateVariable( - param.name, - node.parameterName, + name, + parameterName, typePredicate.parameterName)) { hasReportedError = true; break; @@ -11209,18 +11199,18 @@ namespace ts { pattern: BindingPattern, predicateVariableNode: Node, predicateVariableName: string) { - for (const element of pattern.elements) { - if (element.name.kind === SyntaxKind.Identifier && - (element.name).text === predicateVariableName) { + for (const { name } of pattern.elements) { + if (name.kind === SyntaxKind.Identifier && + (name).text === predicateVariableName) { error(predicateVariableNode, Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, predicateVariableName); return true; } - else if (element.name.kind === SyntaxKind.ArrayBindingPattern || - element.name.kind === SyntaxKind.ObjectBindingPattern) { + else if (name.kind === SyntaxKind.ArrayBindingPattern || + name.kind === SyntaxKind.ObjectBindingPattern) { if (checkBindingPatternForTypePredicateVariable( - element.name, + name, predicateVariableNode, predicateVariableName)) { return true; @@ -11229,19 +11219,6 @@ namespace ts { } } - function isInLegalThisTypePredicatePosition(node: Node): boolean { - if (getTypePredicateParent(node)) { - return true; - } - switch (node.parent.kind) { - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.GetAccessor: - return node === (node.parent as (PropertyDeclaration | GetAccessorDeclaration | PropertySignature)).type; - } - return false; - } - function checkSignatureDeclaration(node: SignatureDeclaration) { // Grammar checking if (node.kind === SyntaxKind.IndexSignature) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1a5b2f3751d..47d85edfbe9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1651,10 +1651,6 @@ "category": "Error", "code": 2518 }, - "A 'this'-based type predicate is only allowed within a class or interface's members, get accessors, or return type positions for functions and methods.": { - "category": "Error", - "code": 2519 - }, "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": { "category": "Error", "code": 2520 From 8cebdcc758ff7b96869423598249461b65bf2b37 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 22 Dec 2015 19:29:49 -0800 Subject: [PATCH 09/31] Add tests for find-all-references --- .../referencesForInheritedProperties3.ts | 15 +++++++ .../referencesForInheritedProperties4.ts | 15 +++++++ .../referencesForInheritedProperties5.ts | 19 +++++++++ .../referencesForInheritedProperties6.ts | 32 ++++++++++++++ .../referencesForInheritedProperties7.ts | 42 +++++++++++++++++++ 5 files changed, 123 insertions(+) create mode 100644 tests/cases/fourslash/referencesForInheritedProperties3.ts create mode 100644 tests/cases/fourslash/referencesForInheritedProperties4.ts create mode 100644 tests/cases/fourslash/referencesForInheritedProperties5.ts create mode 100644 tests/cases/fourslash/referencesForInheritedProperties6.ts create mode 100644 tests/cases/fourslash/referencesForInheritedProperties7.ts diff --git a/tests/cases/fourslash/referencesForInheritedProperties3.ts b/tests/cases/fourslash/referencesForInheritedProperties3.ts new file mode 100644 index 00000000000..134f75da84b --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties3.ts @@ -0,0 +1,15 @@ +/// + +//// interface interface1 extends interface1 { +//// /*1*/doStuff(): void; +//// /*2*/propName: string; +//// } +//// +//// var v: interface1; +//// v./*3*/propName; +//// v./*4*/doStuff(); + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName); + verify.referencesCountIs(2); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForInheritedProperties4.ts b/tests/cases/fourslash/referencesForInheritedProperties4.ts new file mode 100644 index 00000000000..10dcc9c77a2 --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties4.ts @@ -0,0 +1,15 @@ +/// + +//// class class1 extends class1 { +//// /*1*/doStuff() { } +//// /*2*/propName: string; +//// } +//// +//// var c: class1; +//// c./*3*/doStuff(); +//// c./*4*/propName; + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName); + verify.referencesCountIs(2); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForInheritedProperties5.ts b/tests/cases/fourslash/referencesForInheritedProperties5.ts new file mode 100644 index 00000000000..722c5c96f0a --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties5.ts @@ -0,0 +1,19 @@ +/// + +//// interface interface1 extends interface1 { +//// /*1*/doStuff(): void; +//// /*2*/propName: string; +//// } +//// interface interface2 extends interface1 { +//// /*3*/doStuff(): void; +//// /*4*/propName: string; +//// } +//// +//// var v: interface1; +//// v./*5*/propName; +//// v./*6*/doStuff(); + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName); + verify.referencesCountIs(3); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForInheritedProperties6.ts b/tests/cases/fourslash/referencesForInheritedProperties6.ts new file mode 100644 index 00000000000..de6a2f2eba1 --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties6.ts @@ -0,0 +1,32 @@ +/// + +//// class class1 extends class1 { +//// /*1*/doStuff() { } +//// /*2*/propName: string; +//// } +//// class class2 extends class1 { +//// /*3*/doStuff() { } +//// /*4*/propName: string; +//// } +//// +//// var v: class2; +//// v./*5*/propName; +//// v./*6*/doStuff(); + +goTo.marker("1"); +verify.referencesCountIs(1); + +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(2); + +goTo.marker("4"); +verify.referencesCountIs(3); + +goTo.marker("5"); +verify.referencesCountIs(3); + +goTo.marker("6"); +verify.referencesCountIs(2); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForInheritedProperties7.ts b/tests/cases/fourslash/referencesForInheritedProperties7.ts new file mode 100644 index 00000000000..000d4922222 --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties7.ts @@ -0,0 +1,42 @@ +/// + +//// class class1 extends class1 { +//// /*1*/doStuff() { } +//// /*2*/propName: string; +//// } +//// interface interface1 extends interface1 { +//// /*3*/doStuff(): void; +//// /*4*/propName: string; +//// } +//// class class2 extends class1 implements interface1 { +//// /*5*/doStuff() { } +//// /*6*/propName: string; +//// } +//// +//// var v: class2; +//// v./*7*/propName; +//// v./*8*/doStuff(); + +goTo.marker("1"); +verify.referencesCountIs(1); + +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(3); + +goTo.marker("4"); +verify.referencesCountIs(3); + +goTo.marker("5"); +verify.referencesCountIs(3); + +goTo.marker("6"); +verify.referencesCountIs(4); + +goTo.marker("7"); +verify.referencesCountIs(4); + +goTo.marker("8"); +verify.referencesCountIs(3); \ No newline at end of file From 05e5516fc0cd34bbe39f7e2607cffc8e9d63ef26 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 22 Dec 2015 20:02:42 -0800 Subject: [PATCH 10/31] Add rename tests --- .../cases/fourslash/renameInheritedProperties1.ts | 15 +++++++++++++++ .../cases/fourslash/renameInheritedProperties2.ts | 15 +++++++++++++++ .../cases/fourslash/renameInheritedProperties3.ts | 15 +++++++++++++++ .../cases/fourslash/renameInheritedProperties4.ts | 15 +++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 tests/cases/fourslash/renameInheritedProperties1.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties2.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties3.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties4.ts diff --git a/tests/cases/fourslash/renameInheritedProperties1.ts b/tests/cases/fourslash/renameInheritedProperties1.ts new file mode 100644 index 00000000000..f0b2acf3b14 --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties1.ts @@ -0,0 +1,15 @@ +/// + +//// class class1 extends class1 { +//// [|propName|]: string; +//// } +//// +//// var v: class1; +//// v.[|propName|]; + +let ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties2.ts b/tests/cases/fourslash/renameInheritedProperties2.ts new file mode 100644 index 00000000000..ed99ec3e013 --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties2.ts @@ -0,0 +1,15 @@ +/// + +//// class class1 extends class1 { +//// [|doStuff|]() { } +//// } +//// +//// var v: class1; +//// v.[|doStuff|](); + +let ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties3.ts b/tests/cases/fourslash/renameInheritedProperties3.ts new file mode 100644 index 00000000000..17e7785fbc7 --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties3.ts @@ -0,0 +1,15 @@ +/// + +//// interface interface1 extends interface1 { +//// [|propName|]: string; +//// } +//// +//// var v: interface1; +//// v.[|propName|]; + +let ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties4.ts b/tests/cases/fourslash/renameInheritedProperties4.ts new file mode 100644 index 00000000000..ea2f7c40fbf --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties4.ts @@ -0,0 +1,15 @@ +/// + +//// interface interface1 extends interface1 { +//// [|doStuff|](): string; +//// } +//// +//// var v: interface1; +//// v.[|doStuff|](); + +let ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file From 0682a63979b3a8dc66c1c546f16f2ef34a38050d Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 22 Dec 2015 20:26:54 -0800 Subject: [PATCH 11/31] Add find-all-references tests --- .../findAllRefsInheritedProperties1.ts | 25 +++++++++++++ .../findAllRefsInheritedProperties2.ts | 25 +++++++++++++ .../findAllRefsInheritedProperties3.ts | 37 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tests/cases/fourslash/findAllRefsInheritedProperties1.ts create mode 100644 tests/cases/fourslash/findAllRefsInheritedProperties2.ts create mode 100644 tests/cases/fourslash/findAllRefsInheritedProperties3.ts diff --git a/tests/cases/fourslash/findAllRefsInheritedProperties1.ts b/tests/cases/fourslash/findAllRefsInheritedProperties1.ts new file mode 100644 index 00000000000..b2755923d37 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInheritedProperties1.ts @@ -0,0 +1,25 @@ +/// + +//// class class1 extends class1 { +//// [|doStuff|]() { } +//// [|propName|]: string; +//// } +//// +//// var v: class1; +//// v.[|doStuff|](); +//// v.[|propName|]; + +function verifyReferences(query: FourSlashInterface.Range, references: FourSlashInterface.Range[]) { + goTo.position(query.start); + for (const ref of references) { + verify.referencesAtPositionContains(ref); + } +} + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +const [r0, r1, r2, r3] = ranges; +verifyReferences(r0, [r0, r2]); +verifyReferences(r1, [r1, r3]); +verifyReferences(r2, [r0, r2]); +verifyReferences(r3, [r1, r3]); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsInheritedProperties2.ts b/tests/cases/fourslash/findAllRefsInheritedProperties2.ts new file mode 100644 index 00000000000..1ab92c251da --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInheritedProperties2.ts @@ -0,0 +1,25 @@ +/// + +//// interface interface1 extends interface1 { +//// [|doStuff|](): void; // r0 +//// [|propName|]: string; // r1 +//// } +//// +//// var v: interface1; +//// v.[|doStuff|](); // r2 +//// v.[|propName|]; // r3 + +function verifyReferences(query: FourSlashInterface.Range, references: FourSlashInterface.Range[]) { + goTo.position(query.start); + for (const ref of references) { + verify.referencesAtPositionContains(ref); + } +} + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +const [r0, r1, r2, r3] = ranges; +verifyReferences(r0, [r0, r2]); +verifyReferences(r1, [r1, r3]); +verifyReferences(r2, [r0, r2]); +verifyReferences(r3, [r1, r3]); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsInheritedProperties3.ts b/tests/cases/fourslash/findAllRefsInheritedProperties3.ts new file mode 100644 index 00000000000..9a46b08f357 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInheritedProperties3.ts @@ -0,0 +1,37 @@ +/// + +//// class class1 extends class1 { +//// [|doStuff|]() { } // r0 +//// [|propName|]: string; // r1 +//// } +//// interface interface1 extends interface1 { +//// [|doStuff|](): void; // r2 +//// [|propName|]: string; // r3 +//// } +//// class class2 extends class1 implements interface1 { +//// [|doStuff|]() { } // r4 +//// [|propName|]: string; // r5 +//// } +//// +//// var v: class2; +//// v.[|propName|]; // r6 +//// v.[|doStuff|](); // r7 + +function verifyReferences(query: FourSlashInterface.Range, references: FourSlashInterface.Range[]) { + goTo.position(query.start); + for (const ref of references) { + verify.referencesAtPositionContains(ref); + } +} + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +const [r0, r1, r2, r3, r4, r5, r6, r7] = ranges; +verifyReferences(r0, [r0]); +verifyReferences(r1, [r1, r5, r6]); +verifyReferences(r2, [r2, r4, r7]); +verifyReferences(r3, [r3, r5, r6]); +verifyReferences(r4, [r2, r4, r7]); +verifyReferences(r5, [r1, r3, r5, r6]); +verifyReferences(r6, [r1, r3, r5, r6]); +verifyReferences(r7, [r2, r4, r7]); \ No newline at end of file From 9534541829c0609188885f81d24cadc9a09396bf Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 22 Dec 2015 20:35:28 -0800 Subject: [PATCH 12/31] Add documenthightlight tests --- .../documentHighlightAtInheritedProperties1.ts | 13 +++++++++++++ .../documentHighlightAtInheritedProperties2.ts | 13 +++++++++++++ .../documentHighlightAtInheritedProperties3.ts | 17 +++++++++++++++++ .../documentHighlightAtInheritedProperties4.ts | 17 +++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts create mode 100644 tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts create mode 100644 tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts create mode 100644 tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts new file mode 100644 index 00000000000..23f6445a004 --- /dev/null +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts @@ -0,0 +1,13 @@ +/// + +// @Filename: file1.ts +//// interface interface1 extends interface1 { +//// /*1*/doStuff(): void; +//// /*2*/propName: string; +//// } + +let markers = test.markers() +for (let marker of markers) { + goTo.position(marker.position); + verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); +} diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts new file mode 100644 index 00000000000..d4aadf96ed6 --- /dev/null +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts @@ -0,0 +1,13 @@ +/// + +// @Filename: file1.ts +//// class class1 extends class1 { +//// /*1*/doStuff() { } +//// /*2*/propName: string; +//// } + +let markers = test.markers() +for (let marker of markers) { + goTo.position(marker.position); + verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); +} \ No newline at end of file diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts new file mode 100644 index 00000000000..5e94bb387cd --- /dev/null +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts @@ -0,0 +1,17 @@ +/// + +// @Filename: file1.ts +//// interface interface1 extends interface1 { +//// /*1*/doStuff(): void; +//// /*2*/propName: string; +//// } +//// +//// var v: interface1; +//// v./*3*/propName; +//// v./*4*/doStuff(); + +let markers = test.markers() +for (let marker of markers) { + goTo.position(marker.position); + verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); +} diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts new file mode 100644 index 00000000000..50f459ebfdb --- /dev/null +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts @@ -0,0 +1,17 @@ +/// + +// @Filename: file1.ts +//// class class1 extends class1 { +//// /*1*/doStuff() { } +//// /*2*/propName: string; +//// } +//// +//// var c: class1; +//// c./*3*/doStuff(); +//// c./*4*/propName; + +let markers = test.markers() +for (let marker of markers) { + goTo.position(marker.position); + verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); +} From 5544fc0d85b314c949877d74f08c3133a9695883 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 22 Dec 2015 20:39:09 -0800 Subject: [PATCH 13/31] fix crashing when get documentHighlighting --- src/services/services.ts | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 0ffd1138cba..2bda7bf0e72 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5983,14 +5983,37 @@ namespace ts { // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, undefined); } }); return result; } - function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[]): void { + /** + * Find symbol of the given property-name and add the symbol to the given result array + * @param symbol a symbol to start searching for the given propertyName + * @param propertyName a name of property to serach for + * @param result an array of symbol of found property symbols + * @param previousIterationSymbol a symbol from previous iteration of calling this function to prevent infinite revisitng of the same symbol. + * The value of previousIterationSymbol is undefined when the function is first called. + */ + function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[], previousIterationSymbol: Symbol): void { + // If the current symbol is the smae as the previous-iteration symbol, we can just return as the symbol has already been visited + // This is particularly important for the following cases, so that we do not inifinitely visit the same symbol. + // For example: + // interface C extends C { + // /*findRef*/propName: string; + // } + // The first time getPropertySymbolsFromBaseTypes is called when finding-all-references at propName, + // the symbol argument will be the symbol of an interface "C" and previousIterationSymbol is undefined, + // the function will add any found symbol of the property-name, then its sub-routine will call + // getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already + // visited symbol, interface "C", the sub- routine will pass the current symbol as previousIterationSymbol. + if (symbol === previousIterationSymbol) { + return; + } + if (symbol && symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { forEach(symbol.getDeclarations(), declaration => { if (declaration.kind === SyntaxKind.ClassDeclaration) { @@ -6014,7 +6037,7 @@ namespace ts { } // Visit the typeReference as well to see if it directly or indirectly use that property - getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result); + getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result, symbol); } } } @@ -6055,7 +6078,7 @@ namespace ts { // see if any is in the list if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { const result: Symbol[] = []; - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, undefined); return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined); } From 53106cb5ed6b789475320109930df202f22843bb Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 4 Jan 2016 23:00:22 -0800 Subject: [PATCH 14/31] Change logic in identifying SFCs Our logic for detecting SFC vs Element Class had a few issues: * Object Type flag is not actually useful * Parameter arity isn't actually relevant * The check for Element Class should take priority Fixes #6349 and #6353 --- src/compiler/checker.ts | 30 ++++++---- .../reference/tsxElementResolution9.js | 2 +- .../reference/tsxElementResolution9.symbols | 5 +- .../reference/tsxElementResolution9.types | 3 +- .../tsxStatelessFunctionComponents3.js | 37 ++++++++++++ .../tsxStatelessFunctionComponents3.symbols | 48 +++++++++++++++ .../tsxStatelessFunctionComponents3.types | 59 +++++++++++++++++++ .../conformance/jsx/tsxElementResolution9.tsx | 2 +- .../jsx/tsxStatelessFunctionComponents3.tsx | 23 ++++++++ 9 files changed, 191 insertions(+), 18 deletions(-) create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponents3.js create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponents3.symbols create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponents3.types create mode 100644 tests/cases/conformance/jsx/tsxStatelessFunctionComponents3.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fb4af5d7298..a5b96c4a9a8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8248,27 +8248,31 @@ namespace ts { // Get the element instance type (the result of newing or invoking this tag) const elemInstanceType = getJsxElementInstanceType(node); - // Is this is a stateless function component? See if its single signature is - // assignable to the JSX Element Type - const callSignature = getSingleCallSignature(getTypeOfSymbol(sym)); - const callReturnType = callSignature && getReturnTypeOfSignature(callSignature); - let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0])); - if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType) && (paramType.flags & TypeFlags.ObjectType)) { - // Intersect in JSX.IntrinsicAttributes if it exists - const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes); - if (intrinsicAttributes !== unknownType) { - paramType = intersectTypes(intrinsicAttributes, paramType); + const elemClassType = getJsxGlobalElementClassType(); + + if (!elemClassType || !isTypeAssignableTo(elemInstanceType, elemClassType)) { + // Is this is a stateless function component? See if its single signature's return type is + // assignable to the JSX Element Type + const elemType = getTypeOfSymbol(sym); + const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call); + const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0]; + const callReturnType = callSignature && getReturnTypeOfSignature(callSignature); + let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0])); + if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType)) { + // Intersect in JSX.IntrinsicAttributes if it exists + const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes); + if (intrinsicAttributes !== unknownType) { + paramType = intersectTypes(intrinsicAttributes, paramType); + } + return paramType; } - return paramType; } // Issue an error if this return type isn't assignable to JSX.ElementClass - const elemClassType = getJsxGlobalElementClassType(); if (elemClassType) { checkTypeRelatedTo(elemInstanceType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements); } - if (isTypeAny(elemInstanceType)) { return links.resolvedJsxType = elemInstanceType; } diff --git a/tests/baselines/reference/tsxElementResolution9.js b/tests/baselines/reference/tsxElementResolution9.js index bc65bb0bb02..5ad47730e4a 100644 --- a/tests/baselines/reference/tsxElementResolution9.js +++ b/tests/baselines/reference/tsxElementResolution9.js @@ -1,6 +1,6 @@ //// [file.tsx] declare module JSX { - interface Element { } + interface Element { something; } interface IntrinsicElements { } } diff --git a/tests/baselines/reference/tsxElementResolution9.symbols b/tests/baselines/reference/tsxElementResolution9.symbols index e38c64d0847..0aec19a8094 100644 --- a/tests/baselines/reference/tsxElementResolution9.symbols +++ b/tests/baselines/reference/tsxElementResolution9.symbols @@ -2,11 +2,12 @@ declare module JSX { >JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) - interface Element { } + interface Element { something; } >Element : Symbol(Element, Decl(file.tsx, 0, 20)) +>something : Symbol(something, Decl(file.tsx, 1, 20)) interface IntrinsicElements { } ->IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 22)) +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 33)) } interface Obj1 { diff --git a/tests/baselines/reference/tsxElementResolution9.types b/tests/baselines/reference/tsxElementResolution9.types index dd84e6f07b5..b138aa0509e 100644 --- a/tests/baselines/reference/tsxElementResolution9.types +++ b/tests/baselines/reference/tsxElementResolution9.types @@ -2,8 +2,9 @@ declare module JSX { >JSX : any - interface Element { } + interface Element { something; } >Element : Element +>something : any interface IntrinsicElements { } >IntrinsicElements : IntrinsicElements diff --git a/tests/baselines/reference/tsxStatelessFunctionComponents3.js b/tests/baselines/reference/tsxStatelessFunctionComponents3.js new file mode 100644 index 00000000000..d58586dd1ee --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponents3.js @@ -0,0 +1,37 @@ +//// [file.tsx] + +import React = require('react'); + +const Foo = (props: any) =>
; +// Should be OK +const foo = ; + + +// Should be OK +var MainMenu: React.StatelessComponent<{}> = (props) => (
+

Main Menu

+
); + +var App: React.StatelessComponent<{ children }> = ({children}) => ( +
+ +
+); + +//// [file.jsx] +define(["require", "exports", 'react'], function (require, exports, React) { + "use strict"; + var Foo = function (props) { return
; }; + // Should be OK + var foo = ; + // Should be OK + var MainMenu = function (props) { return (
+

Main Menu

+
); }; + var App = function (_a) { + var children = _a.children; + return (
+ +
); + }; +}); diff --git a/tests/baselines/reference/tsxStatelessFunctionComponents3.symbols b/tests/baselines/reference/tsxStatelessFunctionComponents3.symbols new file mode 100644 index 00000000000..4ce502c6a6a --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponents3.symbols @@ -0,0 +1,48 @@ +=== tests/cases/conformance/jsx/file.tsx === + +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +const Foo = (props: any) =>
; +>Foo : Symbol(Foo, Decl(file.tsx, 3, 5)) +>props : Symbol(props, Decl(file.tsx, 3, 13)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45)) + +// Should be OK +const foo = ; +>foo : Symbol(foo, Decl(file.tsx, 5, 5)) +>Foo : Symbol(Foo, Decl(file.tsx, 3, 5)) + + +// Should be OK +var MainMenu: React.StatelessComponent<{}> = (props) => (
+>MainMenu : Symbol(MainMenu, Decl(file.tsx, 9, 3)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 139, 5)) +>props : Symbol(props, Decl(file.tsx, 9, 46)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45)) + +

Main Menu

+>h3 : Symbol(JSX.IntrinsicElements.h3, Decl(react.d.ts, 939, 48)) +>h3 : Symbol(JSX.IntrinsicElements.h3, Decl(react.d.ts, 939, 48)) + +
); +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45)) + +var App: React.StatelessComponent<{ children }> = ({children}) => ( +>App : Symbol(App, Decl(file.tsx, 13, 3)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>StatelessComponent : Symbol(React.StatelessComponent, Decl(react.d.ts, 139, 5)) +>children : Symbol(children, Decl(file.tsx, 13, 35)) +>children : Symbol(children, Decl(file.tsx, 13, 52)) + +
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45)) + + +>MainMenu : Symbol(MainMenu, Decl(file.tsx, 9, 3)) + +
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 927, 45)) + +); diff --git a/tests/baselines/reference/tsxStatelessFunctionComponents3.types b/tests/baselines/reference/tsxStatelessFunctionComponents3.types new file mode 100644 index 00000000000..6531ff737ba --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponents3.types @@ -0,0 +1,59 @@ +=== tests/cases/conformance/jsx/file.tsx === + +import React = require('react'); +>React : typeof React + +const Foo = (props: any) =>
; +>Foo : (props: any) => JSX.Element +>(props: any) =>
: (props: any) => JSX.Element +>props : any +>
: JSX.Element +>div : any + +// Should be OK +const foo = ; +>foo : JSX.Element +> : JSX.Element +>Foo : (props: any) => JSX.Element + + +// Should be OK +var MainMenu: React.StatelessComponent<{}> = (props) => (
+>MainMenu : React.StatelessComponent<{}> +>React : any +>StatelessComponent : React.StatelessComponent

+>(props) => (

Main Menu

) : (props: {}) => JSX.Element +>props : {} +>(

Main Menu

) : JSX.Element +>

Main Menu

: JSX.Element +>div : any + +

Main Menu

+>

Main Menu

: JSX.Element +>h3 : any +>h3 : any + +
); +>div : any + +var App: React.StatelessComponent<{ children }> = ({children}) => ( +>App : React.StatelessComponent<{ children: any; }> +>React : any +>StatelessComponent : React.StatelessComponent

+>children : any +>({children}) => (

) : ({children}: { children: any; }) => JSX.Element +>children : any +>(
) : JSX.Element + +
+>
: JSX.Element +>div : any + + +> : JSX.Element +>MainMenu : React.StatelessComponent<{}> + +
+>div : any + +); diff --git a/tests/cases/conformance/jsx/tsxElementResolution9.tsx b/tests/cases/conformance/jsx/tsxElementResolution9.tsx index 7165f8277b3..4854484a225 100644 --- a/tests/cases/conformance/jsx/tsxElementResolution9.tsx +++ b/tests/cases/conformance/jsx/tsxElementResolution9.tsx @@ -1,7 +1,7 @@ //@filename: file.tsx //@jsx: preserve declare module JSX { - interface Element { } + interface Element { something; } interface IntrinsicElements { } } diff --git a/tests/cases/conformance/jsx/tsxStatelessFunctionComponents3.tsx b/tests/cases/conformance/jsx/tsxStatelessFunctionComponents3.tsx new file mode 100644 index 00000000000..48ce5fb5efb --- /dev/null +++ b/tests/cases/conformance/jsx/tsxStatelessFunctionComponents3.tsx @@ -0,0 +1,23 @@ +// @filename: file.tsx +// @jsx: preserve +// @module: amd +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +const Foo = (props: any) =>
; +// Should be OK +const foo = ; + + +// Should be OK +var MainMenu: React.StatelessComponent<{}> = (props) => (
+

Main Menu

+
); + +var App: React.StatelessComponent<{ children }> = ({children}) => ( +
+ +
+); \ No newline at end of file From 7d31b5c8a3e4f05e59ce86519306432ff420c268 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 6 Jan 2016 10:27:31 -0800 Subject: [PATCH 15/31] Fix find all refs in shorthand properties for imports and exports --- src/compiler/checker.ts | 10 +++++- src/compiler/types.ts | 1 + src/services/services.ts | 31 ++++++++++++++----- .../cases/fourslash/renameImportAndExport.ts | 10 ++++++ .../fourslash/renameImportAndShorthand.ts | 10 ++++++ .../renameImportNamespaceAndShorthand.ts | 10 ++++++ 6 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 tests/cases/fourslash/renameImportAndExport.ts create mode 100644 tests/cases/fourslash/renameImportAndShorthand.ts create mode 100644 tests/cases/fourslash/renameImportNamespaceAndShorthand.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e4ad3339887..201ad348bed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -82,6 +82,7 @@ namespace ts { getSymbolsInScope, getSymbolAtLocation, getShorthandAssignmentValueSymbol, + getExportSpecifierLocalTargetSymbol, getTypeAtLocation: getTypeOfNode, typeToString, getSymbolDisplayBuilder, @@ -15007,11 +15008,18 @@ namespace ts { // This is necessary as an identifier in short-hand property assignment can contains two meaning: // property name and property value. if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { - return resolveEntityName((location).name, SymbolFlags.Value); + return resolveEntityName((location).name, SymbolFlags.Value | SymbolFlags.Alias); } return undefined; } + /** Returns the target of an export specifier without following aliases */ + function getExportSpecifierLocalTargetSymbol(node: ExportSpecifier): Symbol { + return (node.parent.parent).moduleSpecifier ? + getExternalModuleMember(node.parent.parent, node) : + resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + } + function getTypeOfNode(node: Node): Type { if (isInsideWithStatementBody(node)) { // We cannot answer semantic questions within a with block, do not proceed any further diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 24f70373a8a..3d074f5048c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1725,6 +1725,7 @@ namespace ts { getSymbolAtLocation(node: Node): Symbol; getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[]; getShorthandAssignmentValueSymbol(location: Node): Symbol; + getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol; getTypeAtLocation(node: Node): Type; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; diff --git a/src/services/services.ts b/src/services/services.ts index 0fd4df19907..f89ba4e94fa 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5490,10 +5490,8 @@ namespace ts { }; } - function isImportOrExportSpecifierImportSymbol(symbol: Symbol) { - return (symbol.flags & SymbolFlags.Alias) && forEach(symbol.declarations, declaration => { - return declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ExportSpecifier; - }); + function isImportSpecifierSymbol(symbol: Symbol) { + return (symbol.flags & SymbolFlags.Alias) && forEach(symbol.declarations, declaration => declaration.kind === SyntaxKind.ImportSpecifier); } function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string { @@ -5937,8 +5935,16 @@ namespace ts { let result = [symbol]; // If the symbol is an alias, add what it alaises to the list - if (isImportOrExportSpecifierImportSymbol(symbol)) { - result.push(typeChecker.getAliasedSymbol(symbol)); + if (isImportSpecifierSymbol(symbol)) { + result.push(typeChecker.getAliasedSymbol(symbol)); + } + + // For export specifiers, it can be a local symbol, e.g. + // import {a} from "mod"; + // export {a as somethingElse} + // We want the local target of the export (i.e. the import symbol) and not the final target (i.e. "mod".a) + if (location.parent.kind === SyntaxKind.ExportSpecifier) { + result.push(typeChecker.getExportSpecifierLocalTargetSymbol(location.parent)); } // If the location is in a context sensitive location (i.e. in an object literal) try @@ -6028,13 +6034,24 @@ namespace ts { // If the reference symbol is an alias, check if what it is aliasing is one of the search // symbols. - if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) { + if (isImportSpecifierSymbol(referenceSymbol)) { const aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol); if (searchSymbols.indexOf(aliasedSymbol) >= 0) { return aliasedSymbol; } } + // For export specifiers, it can be a local symbol, e.g. + // import {a} from "mod"; + // export {a as somethingElse} + // We want the local target of the export (i.e. the import symbol) and not the final target (i.e. "mod".a) + if (referenceLocation.parent.kind === SyntaxKind.ExportSpecifier) { + const aliasedSymbol = typeChecker.getExportSpecifierLocalTargetSymbol(referenceLocation.parent); + if (searchSymbols.indexOf(aliasedSymbol) >= 0) { + return aliasedSymbol; + } + } + // If the reference location is in an object literal, try to get the contextual type for the // object literal, lookup the property symbol in the contextual type, and use this symbol to // compare to our searchSymbol diff --git a/tests/cases/fourslash/renameImportAndExport.ts b/tests/cases/fourslash/renameImportAndExport.ts new file mode 100644 index 00000000000..495e15c1e7e --- /dev/null +++ b/tests/cases/fourslash/renameImportAndExport.ts @@ -0,0 +1,10 @@ +/// + +////import [|a|] from "module"; +////export { [|a|] }; + +let ranges = test.ranges() +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} diff --git a/tests/cases/fourslash/renameImportAndShorthand.ts b/tests/cases/fourslash/renameImportAndShorthand.ts new file mode 100644 index 00000000000..bc4746aebdd --- /dev/null +++ b/tests/cases/fourslash/renameImportAndShorthand.ts @@ -0,0 +1,10 @@ +/// + +////import [|foo|] from 'bar'; +////const bar = { [|foo|] }; + +let ranges = test.ranges() +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} diff --git a/tests/cases/fourslash/renameImportNamespaceAndShorthand.ts b/tests/cases/fourslash/renameImportNamespaceAndShorthand.ts new file mode 100644 index 00000000000..a6b06c11408 --- /dev/null +++ b/tests/cases/fourslash/renameImportNamespaceAndShorthand.ts @@ -0,0 +1,10 @@ +/// + +////import * as [|foo|] from 'bar'; +////const bar = { [|foo|] }; + +let ranges = test.ranges() +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} From f09628900a37046d1c29af8338dffdea87d289db Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 6 Jan 2016 10:48:24 -0800 Subject: [PATCH 16/31] Add new test for import..require --- tests/cases/fourslash/renameImportRequire.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/cases/fourslash/renameImportRequire.ts diff --git a/tests/cases/fourslash/renameImportRequire.ts b/tests/cases/fourslash/renameImportRequire.ts new file mode 100644 index 00000000000..c26cc80b616 --- /dev/null +++ b/tests/cases/fourslash/renameImportRequire.ts @@ -0,0 +1,12 @@ +/// + +////import [|e|] = require("mod4"); +////[|e|]; +////a = { [|e|] }; +////export { [|e|] }; + +let ranges = test.ranges() +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} From 9b13a0c5b9796a10d9847068f2cdd89bd8523468 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 6 Jan 2016 10:58:57 -0800 Subject: [PATCH 17/31] Better name for checkTypePredicate helper function checkBindingPatternForTypeVariable -> checkIfTypeVariableIsDeclaredInBindingPattern --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ce40f8b7348..6b508c57dc6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11164,7 +11164,7 @@ namespace ts { for (const { name } of parent.parameters) { if ((name.kind === SyntaxKind.ObjectBindingPattern || name.kind === SyntaxKind.ArrayBindingPattern) && - checkBindingPatternForTypePredicateVariable( + checkIfTypePredicateVariableIsDeclaredInBindingPattern( name, parameterName, typePredicate.parameterName)) { @@ -11195,7 +11195,7 @@ namespace ts { } } - function checkBindingPatternForTypePredicateVariable( + function checkIfTypePredicateVariableIsDeclaredInBindingPattern( pattern: BindingPattern, predicateVariableNode: Node, predicateVariableName: string) { @@ -11209,7 +11209,7 @@ namespace ts { } else if (name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern) { - if (checkBindingPatternForTypePredicateVariable( + if (checkIfTypePredicateVariableIsDeclaredInBindingPattern( name, predicateVariableNode, predicateVariableName)) { From cf8daffea1083c0fcf41ace28fb69e1a97e8f976 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 6 Jan 2016 13:21:03 -0800 Subject: [PATCH 18/31] Properly cache JSX element types for SFC expressions --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a5b96c4a9a8..9b56824ec15 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8264,7 +8264,7 @@ namespace ts { if (intrinsicAttributes !== unknownType) { paramType = intersectTypes(intrinsicAttributes, paramType); } - return paramType; + return links.resolvedJsxType = paramType; } } From cdc33f51d2c79a655ed09769b357d1636637f29e Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 7 Jan 2016 13:30:54 -0800 Subject: [PATCH 19/31] Code review comments --- src/services/services.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index f89ba4e94fa..0096838f314 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5491,7 +5491,7 @@ namespace ts { } function isImportSpecifierSymbol(symbol: Symbol) { - return (symbol.flags & SymbolFlags.Alias) && forEach(symbol.declarations, declaration => declaration.kind === SyntaxKind.ImportSpecifier); + return (symbol.flags & SymbolFlags.Alias) && !!getDeclarationOfKind(symbol, SyntaxKind.ImportSpecifier); } function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string { @@ -5939,10 +5939,11 @@ namespace ts { result.push(typeChecker.getAliasedSymbol(symbol)); } - // For export specifiers, it can be a local symbol, e.g. + // For export specifiers, the exported name can be refering to a local symbol, e.g.: // import {a} from "mod"; // export {a as somethingElse} - // We want the local target of the export (i.e. the import symbol) and not the final target (i.e. "mod".a) + // We want the *local* declaration of 'a' as declared in the import, + // *not* as declared within "mod" (or farther) if (location.parent.kind === SyntaxKind.ExportSpecifier) { result.push(typeChecker.getExportSpecifierLocalTargetSymbol(location.parent)); } From 9b01783e2d6cf94ec0aa720b6e1ef6f03c59e1ba Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 7 Jan 2016 13:31:14 -0800 Subject: [PATCH 20/31] Add test for renaming accorss modules using export= --- .../fourslash/renameImportOfExportEquals.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/cases/fourslash/renameImportOfExportEquals.ts diff --git a/tests/cases/fourslash/renameImportOfExportEquals.ts b/tests/cases/fourslash/renameImportOfExportEquals.ts new file mode 100644 index 00000000000..9d71ee907c8 --- /dev/null +++ b/tests/cases/fourslash/renameImportOfExportEquals.ts @@ -0,0 +1,18 @@ +/// + +////declare namespace N { +//// export var x: number; +////} +////declare module "mod" { +//// export = N; +////} +////declare module "test" { +//// import * as [|N|] from "mod"; +//// export { [|N|] }; // Renaming N here would rename +////} + +let ranges = test.ranges() +for (let range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} From 6dfe29ec31e6004dbdaf17fa24e6f4ef9536e4ac Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Fri, 8 Jan 2016 03:34:43 -0800 Subject: [PATCH 21/31] Add tests --- ...documentHighlightAtInheritedProperties5.ts | 30 +++++++++++++++++++ ...documentHighlightAtInheritedProperties6.ts | 30 +++++++++++++++++++ .../findAllRefsInheritedProperties4.ts | 30 +++++++++++++++++++ .../findAllRefsInheritedProperties5.ts | 30 +++++++++++++++++++ .../referencesForInheritedProperties8.ts | 27 +++++++++++++++++ .../referencesForInheritedProperties9.ts | 21 +++++++++++++ .../fourslash/renameInheritedProperties1.ts | 4 +-- .../fourslash/renameInheritedProperties5.ts | 17 +++++++++++ .../fourslash/renameInheritedProperties6.ts | 17 +++++++++++ .../fourslash/renameInheritedProperties7.ts | 19 ++++++++++++ .../fourslash/renameInheritedProperties8.ts | 19 ++++++++++++ 11 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts create mode 100644 tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts create mode 100644 tests/cases/fourslash/findAllRefsInheritedProperties4.ts create mode 100644 tests/cases/fourslash/findAllRefsInheritedProperties5.ts create mode 100644 tests/cases/fourslash/referencesForInheritedProperties8.ts create mode 100644 tests/cases/fourslash/referencesForInheritedProperties9.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties5.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties6.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties7.ts create mode 100644 tests/cases/fourslash/renameInheritedProperties8.ts diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts new file mode 100644 index 00000000000..b5f4cbb00a7 --- /dev/null +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts @@ -0,0 +1,30 @@ +/// + +// @Filename: file1.ts +//// interface C extends D { +//// /*0*/prop0: string; +//// /*1*/prop1: number; +//// } +//// +//// interface D extends C { +//// /*2*/prop0: string; +//// /*3*/prop1: number; +//// } +//// +//// var d: D; +//// d./*4*/prop1; + +goTo.marker("0"); +verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); + +goTo.marker("1"); +verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); + +goTo.marker("2"); +verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); + +goTo.marker("3"); +verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); + +goTo.marker("4"); +verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); \ No newline at end of file diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts new file mode 100644 index 00000000000..8f1089e567d --- /dev/null +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts @@ -0,0 +1,30 @@ +/// + +// @Filename: file1.ts +//// class C extends D { +//// /*0*/prop0: string; +//// /*1*/prop1: string; +//// } +//// +//// class D extends C { +//// /*2*/prop0: string; +//// /*3*/prop1: string; +//// } +//// +//// var d: D; +//// d./*4*/prop1; + +goTo.marker("0"); +verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); + +goTo.marker("1"); +verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); + +goTo.marker("2"); +verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); + +goTo.marker("3"); +verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); + +goTo.marker("4"); +verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsInheritedProperties4.ts b/tests/cases/fourslash/findAllRefsInheritedProperties4.ts new file mode 100644 index 00000000000..bcd41331f73 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInheritedProperties4.ts @@ -0,0 +1,30 @@ +/// + +//// interface C extends D { +//// [|prop0|]: string; // r0 +//// [|prop1|]: number; // r1 +//// } +//// +//// interface D extends C { +//// [|prop0|]: string; // r2 +//// } +//// +//// var d: D; +//// d.[|prop0|]; // r3 +//// d.[|prop1|]; // r4 + +function verifyReferences(query: FourSlashInterface.Range, references: FourSlashInterface.Range[]) { + goTo.position(query.start); + for (const ref of references) { + verify.referencesAtPositionContains(ref); + } +} + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +const [r0, r1, r2, r3, r4] = ranges; +verifyReferences(r0, [r0, r2, r3]); +verifyReferences(r1, [r1]); +verifyReferences(r2, [r0, r2, r3]); +verifyReferences(r3, [r0, r2, r3]); +verifyReferences(r4, []); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsInheritedProperties5.ts b/tests/cases/fourslash/findAllRefsInheritedProperties5.ts new file mode 100644 index 00000000000..d4e02a36b09 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInheritedProperties5.ts @@ -0,0 +1,30 @@ +/// + +//// class C extends D { +//// [|prop0|]: string; // r0 +//// [|prop1|]: number; // r1 +//// } +//// +//// class D extends C { +//// [|prop0|]: string; // r2 +//// } +//// +//// var d: D; +//// d.[|prop0|]; // r3 +//// d.[|prop1|]; // r4 + +function verifyReferences(query: FourSlashInterface.Range, references: FourSlashInterface.Range[]) { + goTo.position(query.start); + for (const ref of references) { + verify.referencesAtPositionContains(ref); + } +} + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +const [r0, r1, r2, r3, r4] = ranges; +verifyReferences(r0, [r0]); +verifyReferences(r1, [r1]); +verifyReferences(r2, [r2, r3]); +verifyReferences(r3, [r2, r3]); +verifyReferences(r4, []); diff --git a/tests/cases/fourslash/referencesForInheritedProperties8.ts b/tests/cases/fourslash/referencesForInheritedProperties8.ts new file mode 100644 index 00000000000..f34b327a472 --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties8.ts @@ -0,0 +1,27 @@ +/// + +//// interface C extends D { +//// /*0*/propD: number; +//// } +//// interface D extends C { +//// /*1*/propD: string; +//// /*3*/propC: number; +//// } +//// var d: D; +//// d./*2*/propD; +//// d./*4*/propC; + +goTo.marker("0"); +verify.referencesCountIs(3); + +goTo.marker("1"); +verify.referencesCountIs(3); + +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(2); + +goTo.marker("4"); +verify.referencesCountIs(2); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForInheritedProperties9.ts b/tests/cases/fourslash/referencesForInheritedProperties9.ts new file mode 100644 index 00000000000..b348d6e8cf6 --- /dev/null +++ b/tests/cases/fourslash/referencesForInheritedProperties9.ts @@ -0,0 +1,21 @@ +/// + +//// class D extends C { +//// /*0*/prop1: string; +//// } +//// +//// class C extends D { +//// /*1*/prop1: string; +//// } +//// +//// var c: C; +//// c./*2*/prop1; + +goTo.marker("0"); +verify.referencesCountIs(1); + +goTo.marker("1"); +verify.referencesCountIs(2) + +goTo.marker("2"); +verify.referencesCountIs(2) \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties1.ts b/tests/cases/fourslash/renameInheritedProperties1.ts index f0b2acf3b14..4698fe3d97b 100644 --- a/tests/cases/fourslash/renameInheritedProperties1.ts +++ b/tests/cases/fourslash/renameInheritedProperties1.ts @@ -7,9 +7,9 @@ //// var v: class1; //// v.[|propName|]; -let ranges = test.ranges(); +const ranges = test.ranges(); verify.assertHasRanges(ranges); -for (let range of ranges) { +for (const range of ranges) { goTo.position(range.start); verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); } \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties5.ts b/tests/cases/fourslash/renameInheritedProperties5.ts new file mode 100644 index 00000000000..45058827747 --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties5.ts @@ -0,0 +1,17 @@ +/// + +//// interface C extends D { +//// propC: number; +//// } +//// interface D extends C { +//// [|propD|]: string; +//// } +//// var d: D; +//// d.[|propD|]; + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (const range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} diff --git a/tests/cases/fourslash/renameInheritedProperties6.ts b/tests/cases/fourslash/renameInheritedProperties6.ts new file mode 100644 index 00000000000..6bdd32ce3e0 --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties6.ts @@ -0,0 +1,17 @@ +/// + +//// interface C extends D { +//// propD: number; +//// } +//// interface D extends C { +//// [|propC|]: number; +//// } +//// var d: D; +//// d.[|propC|]; + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (const range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties7.ts b/tests/cases/fourslash/renameInheritedProperties7.ts new file mode 100644 index 00000000000..a2f8c5a2b51 --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties7.ts @@ -0,0 +1,19 @@ +/// + +//// class C extends D { +//// [|prop1|]: string; +//// } +//// +//// class D extends C { +//// prop1: string; +//// } +//// +//// var c: C; +//// c.[|prop1|]; + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (const range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file diff --git a/tests/cases/fourslash/renameInheritedProperties8.ts b/tests/cases/fourslash/renameInheritedProperties8.ts new file mode 100644 index 00000000000..119e1a477aa --- /dev/null +++ b/tests/cases/fourslash/renameInheritedProperties8.ts @@ -0,0 +1,19 @@ +/// + +//// class C implements D { +//// [|prop1|]: string; +//// } +//// +//// interface D extends C { +//// [|prop1|]: string; +//// } +//// +//// var c: C; +//// c.[|prop1|]; + +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +for (const range of ranges) { + goTo.position(range.start); + verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false); +} \ No newline at end of file From 68f6d0c1ad840499cf64f2d087a968063551138d Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Fri, 8 Jan 2016 03:34:57 -0800 Subject: [PATCH 22/31] Address PR feedback --- src/services/services.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 2bda7bf0e72..ce41db2205f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5983,7 +5983,7 @@ namespace ts { // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, undefined); + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, {}); } }); @@ -5995,10 +5995,11 @@ namespace ts { * @param symbol a symbol to start searching for the given propertyName * @param propertyName a name of property to serach for * @param result an array of symbol of found property symbols - * @param previousIterationSymbol a symbol from previous iteration of calling this function to prevent infinite revisitng of the same symbol. + * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisitng of the same symbol. * The value of previousIterationSymbol is undefined when the function is first called. */ - function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[], previousIterationSymbol: Symbol): void { + function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[], + previousIterationSymbolsCache: SymbolTable): void { // If the current symbol is the smae as the previous-iteration symbol, we can just return as the symbol has already been visited // This is particularly important for the following cases, so that we do not inifinitely visit the same symbol. // For example: @@ -6010,7 +6011,7 @@ namespace ts { // the function will add any found symbol of the property-name, then its sub-routine will call // getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already // visited symbol, interface "C", the sub- routine will pass the current symbol as previousIterationSymbol. - if (symbol === previousIterationSymbol) { + if (previousIterationSymbolsCache && previousIterationSymbolsCache[symbol.name] === symbol) { return; } @@ -6037,7 +6038,8 @@ namespace ts { } // Visit the typeReference as well to see if it directly or indirectly use that property - getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result, symbol); + previousIterationSymbolsCache[symbol.name] = symbol; + getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result, previousIterationSymbolsCache); } } } @@ -6078,7 +6080,7 @@ namespace ts { // see if any is in the list if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { const result: Symbol[] = []; - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, undefined); + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, {}); return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined); } From dd58228861f45847c2b8036a3fb880464ae9209a Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 11 Jan 2016 21:34:52 -0800 Subject: [PATCH 23/31] add no-default-lib tag to core libraries --- Jakefile.js | 8 ++++---- src/lib/core.d.ts | 2 -- src/lib/header.d.ts | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 src/lib/header.d.ts diff --git a/Jakefile.js b/Jakefile.js index b62cbed3279..0749ba8cc26 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -163,13 +163,13 @@ var harnessSources = harnessCoreSources.concat([ })); var librarySourceMap = [ - { target: "lib.core.d.ts", sources: ["core.d.ts"] }, + { target: "lib.core.d.ts", sources: ["header.d.ts", "core.d.ts"] }, { target: "lib.dom.d.ts", sources: ["importcore.d.ts", "intl.d.ts", "dom.generated.d.ts"], }, { target: "lib.webworker.d.ts", sources: ["importcore.d.ts", "intl.d.ts", "webworker.generated.d.ts"], }, { target: "lib.scriptHost.d.ts", sources: ["importcore.d.ts", "scriptHost.d.ts"], }, - { target: "lib.d.ts", sources: ["core.d.ts", "intl.d.ts", "dom.generated.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"], }, - { target: "lib.core.es6.d.ts", sources: ["core.d.ts", "es6.d.ts"]}, - { target: "lib.es6.d.ts", sources: ["es6.d.ts", "core.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"] } + { target: "lib.d.ts", sources: ["header.d.ts", "core.d.ts", "intl.d.ts", "dom.generated.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"], }, + { target: "lib.core.es6.d.ts", sources: ["header.d.ts", "core.d.ts", "es6.d.ts"]}, + { target: "lib.es6.d.ts", sources: ["header.d.ts", "es6.d.ts", "core.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"] } ]; var libraryTargets = librarySourceMap.map(function (f) { diff --git a/src/lib/core.d.ts b/src/lib/core.d.ts index 12df449931e..dbd4d37ef96 100644 --- a/src/lib/core.d.ts +++ b/src/lib/core.d.ts @@ -1,5 +1,3 @@ -/// - ///////////////////////////// /// ECMAScript APIs ///////////////////////////// diff --git a/src/lib/header.d.ts b/src/lib/header.d.ts new file mode 100644 index 00000000000..129e4739a83 --- /dev/null +++ b/src/lib/header.d.ts @@ -0,0 +1 @@ +/// From 1a964394b2440d4ddc23b8fed89b16bd485da5f8 Mon Sep 17 00:00:00 2001 From: vladima Date: Mon, 11 Jan 2016 22:32:05 -0800 Subject: [PATCH 24/31] accept baselines --- .../reference/variableDeclarationInStrictMode1.errors.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index 328e080fbaa..9dd9a8d41a1 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -1,4 +1,4 @@ -lib.d.ts(29,18): error TS2300: Duplicate identifier 'eval'. +lib.d.ts(28,18): error TS2300: Duplicate identifier 'eval'. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS1100: Invalid use of 'eval' in strict mode. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Duplicate identifier 'eval'. From a9f2cb6d6e791a0c1e7d588369da4bae6811653b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Jan 2016 09:31:06 -0800 Subject: [PATCH 25/31] Make `parseTypeOrTypePredicate` terser. --- src/compiler/parser.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index eaeb6452044..bfa5fb6ee1a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2541,11 +2541,7 @@ namespace ts { } function parseTypeOrTypePredicate(): TypeNode { - let typePredicateVariable: Identifier; - if (isIdentifier()) { - typePredicateVariable = tryParse(parseTypePredicatePrefix); - } - + const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); const type = parseType(); if (typePredicateVariable) { const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); From 2294ef88919ef9175ef76c63c005af2d3e286f80 Mon Sep 17 00:00:00 2001 From: pcbro <2bux89+dk3zspjmuh16o@sharklasers.com> Date: Wed, 13 Jan 2016 23:43:41 +0100 Subject: [PATCH 26/31] Update utilities.ts --- src/compiler/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7bc708c7178..3553430bcde 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -779,7 +779,7 @@ namespace ts { * Given an super call\property node returns a closest node where either * - super call\property is legal in the node and not legal in the parent node the node. * i.e. super call is legal in constructor but not legal in the class body. - * - node is arrow function (so caller might need to call getSuperContainer in case if he needs to climb higher) + * - node is arrow function (so caller might need to call getSuperContainer in case it needs to climb higher) * - super call\property is definitely illegal in the node (but might be legal in some subnode) * i.e. super property access is illegal in function declaration but can be legal in the statement list */ From 4d065ffbf8a57d93bdaa7aac85e3fdeea004bbcf Mon Sep 17 00:00:00 2001 From: pcbro <2bux89+dk3zspjmuh16o@sharklasers.com> Date: Wed, 13 Jan 2016 17:01:53 -0600 Subject: [PATCH 27/31] Use gender-neutral language --- lib/typescript.js | 2 +- lib/typescriptServices.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index 1e2f51f5aae..6608f585b61 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -5037,7 +5037,7 @@ var ts; * Given an super call\property node returns a closest node where either * - super call\property is legal in the node and not legal in the parent node the node. * i.e. super call is legal in constructor but not legal in the class body. - * - node is arrow function (so caller might need to call getSuperContainer in case if he needs to climb higher) + * - node is arrow function (so caller might need to call getSuperContainer in case it needs to climb higher) * - super call\property is definitely illegal in the node (but might be legal in some subnode) * i.e. super property access is illegal in function declaration but can be legal in the statement list */ diff --git a/lib/typescriptServices.js b/lib/typescriptServices.js index 1e2f51f5aae..6608f585b61 100644 --- a/lib/typescriptServices.js +++ b/lib/typescriptServices.js @@ -5037,7 +5037,7 @@ var ts; * Given an super call\property node returns a closest node where either * - super call\property is legal in the node and not legal in the parent node the node. * i.e. super call is legal in constructor but not legal in the class body. - * - node is arrow function (so caller might need to call getSuperContainer in case if he needs to climb higher) + * - node is arrow function (so caller might need to call getSuperContainer in case it needs to climb higher) * - super call\property is definitely illegal in the node (but might be legal in some subnode) * i.e. super property access is illegal in function declaration but can be legal in the statement list */ From 3391abf51ac009ab6c4572a2ea31f781fbc9e623 Mon Sep 17 00:00:00 2001 From: Yui T Date: Wed, 13 Jan 2016 15:10:29 -0800 Subject: [PATCH 28/31] Address PR --- src/services/services.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index ce41db2205f..9c131f8f044 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5983,7 +5983,7 @@ namespace ts { // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, {}); + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {}); } }); @@ -6000,8 +6000,8 @@ namespace ts { */ function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[], previousIterationSymbolsCache: SymbolTable): void { - // If the current symbol is the smae as the previous-iteration symbol, we can just return as the symbol has already been visited - // This is particularly important for the following cases, so that we do not inifinitely visit the same symbol. + // If the current symbol is the same as the previous-iteration symbol, we can just return the symbol that has already been visited + // This is particularly important for the following cases, so that we do not infinitely visit the same symbol. // For example: // interface C extends C { // /*findRef*/propName: string; @@ -6080,7 +6080,7 @@ namespace ts { // see if any is in the list if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { const result: Symbol[] = []; - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, {}); + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {}); return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined); } From d4a04a11d2931341baac7a76d61de63b08f606a4 Mon Sep 17 00:00:00 2001 From: Yui T Date: Wed, 13 Jan 2016 16:48:48 -0800 Subject: [PATCH 29/31] Address PR --- src/services/services.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 9c131f8f044..dcc01300e96 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6010,8 +6010,8 @@ namespace ts { // the symbol argument will be the symbol of an interface "C" and previousIterationSymbol is undefined, // the function will add any found symbol of the property-name, then its sub-routine will call // getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already - // visited symbol, interface "C", the sub- routine will pass the current symbol as previousIterationSymbol. - if (previousIterationSymbolsCache && previousIterationSymbolsCache[symbol.name] === symbol) { + // visited symbol, interface "C", the sub-routine will pass the current symbol as previousIterationSymbol. + if (hasProperty(previousIterationSymbolsCache, symbol.name)) { return; } From 94eb1079fd4ed64d43f36f7ad7d134b3a54d8aa1 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 14 Jan 2016 10:14:25 -0800 Subject: [PATCH 30/31] Print the names of files being linted. --- Jakefile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Jakefile.js b/Jakefile.js index 0749ba8cc26..7024ad2afdf 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -893,6 +893,7 @@ function getLinterOptions() { function lintFileContents(options, path, contents) { var ll = new Linter(path, contents, options); + console.log("Linting '" + path + "'.") return ll.lint(); } From 62c3bfb1fb6714fc383379caae8b55d81bf62fbe Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 14 Jan 2016 10:17:32 -0800 Subject: [PATCH 31/31] Temporarily use an older nightly so builds can succeed. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 261cdfa64b7..f0ba128a919 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "istanbul": "latest", "mocha-fivemat-progress-reporter": "latest", "tslint": "next", - "typescript": "next", + "typescript": "1.8.0-dev.20160113", "tsd": "latest" }, "scripts": {