From ea30c68128499f649be64711ae94b7946d16acff Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 19 Jan 2015 18:07:54 -0800 Subject: [PATCH 01/17] Rudimentary, but imperfect, lexical classification for templates. --- src/services/services.ts | 95 +++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index def895880e6..d585722e7ef 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1143,6 +1143,9 @@ module ts { InMultiLineCommentTrivia, InSingleQuoteStringLiteral, InDoubleQuoteStringLiteral, + InTemplateHeadLiteral, // this could also be a NoSubstitutionTemplateLiteral + InTemplateMiddleLiteral, //this could also be a TemplateTail + InTemplateSubstitutionPosition, } export enum TokenClass { @@ -5650,12 +5653,12 @@ module ts { // if there are more cases we want the classifier to be better at. return true; } - - // 'classifyKeywordsInGenerics' should be 'true' when a syntactic classifier is not present. - function getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult { + + function getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult { var offset = 0; var token = SyntaxKind.Unknown; var lastNonTriviaToken = SyntaxKind.Unknown; + var templateStack: SyntaxKind[]; // If we're in a string literal, then prepend: "\ // (and a newline). That way when we lex we'll think we're still in a string literal. @@ -5675,6 +5678,21 @@ module ts { text = "/*\n" + text; offset = 3; break; + case EndOfLineState.InTemplateHeadLiteral: + if (syntacticClassifierAbsent) { + text = "`\n" + text; + offset = 2; + } + break; + case EndOfLineState.InTemplateMiddleLiteral: + if (syntacticClassifierAbsent) { + text = "${\n" + text; + offset = 3; + } + // fallthrough + case EndOfLineState.InTemplateSubstitutionPosition: + templateStack = [SyntaxKind.TemplateHead]; + break; } scanner.setText(text); @@ -5739,12 +5757,50 @@ module ts { token === SyntaxKind.StringKeyword || token === SyntaxKind.NumberKeyword || token === SyntaxKind.BooleanKeyword) { - if (angleBracketStack > 0 && !classifyKeywordsInGenerics) { - // If it looks like we're could be in something generic, don't classify this - // as a keyword. We may just get overwritten by the syntactic classifier, - // causing a noisy experience for the user. - token = SyntaxKind.Identifier; - } + if (angleBracketStack > 0 && !syntacticClassifierAbsent) { + // If it looks like we're could be in something generic, don't classify this + // as a keyword. We may just get overwritten by the syntactic classifier, + // causing a noisy experience for the user. + token = SyntaxKind.Identifier; + } + } + else if (token === SyntaxKind.TemplateHead && syntacticClassifierAbsent) { + if (!templateStack) { + templateStack = [token]; + } + else { + templateStack.push(token); + } + } + else if (token === SyntaxKind.OpenBraceToken && syntacticClassifierAbsent) { + // If we don't have anything on the template stack, + // then we aren't trying to keep track of a previously scanned template head. + if (templateStack && templateStack.length > 0) { + templateStack.push(token); + } + } + else if (token === SyntaxKind.CloseBraceToken && syntacticClassifierAbsent) { + // If we don't have anything on the template stack, + // then we aren't trying to keep track of a previously scanned template head. + if (templateStack && templateStack.length > 0) { + var lastTemplateStackToken = lastOrUndefined(templateStack); + + if (lastTemplateStackToken === SyntaxKind.TemplateHead) { + token = scanner.reScanTemplateToken(); + + // Only pop on a TemplateTail; a TemplateMiddle indicates there is more for us. + if (token === SyntaxKind.TemplateTail) { + templateStack.pop(); + } + else { + Debug.assert(token === SyntaxKind.TemplateMiddle, "Should have been a template middle. Was " + token); + } + } + else { + Debug.assert(token === SyntaxKind.CloseBraceToken, "Should have been an open brace. Was: " + token); + templateStack.pop(); + } + } } lastNonTriviaToken = token; @@ -5760,7 +5816,7 @@ module ts { var start = scanner.getTokenPos(); var end = scanner.getTextPos(); - addResult(end - start, classFromKind(token)); + addResult(end - start, classFromKind(token, syntacticClassifierAbsent)); if (end >= text.length) { if (token === SyntaxKind.StringLiteral) { @@ -5789,6 +5845,19 @@ module ts { result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; } } + else if (isTemplateLiteralKind(token) && syntacticClassifierAbsent) { + if (scanner.isUnterminated()) { + if (token === SyntaxKind.TemplateMiddle) { + result.finalLexState = EndOfLineState.InTemplateMiddleLiteral; + } + else { + result.finalLexState = EndOfLineState.InTemplateHeadLiteral; + } + } + } + else if (templateStack && templateStack.length > 0 && lastOrUndefined(templateStack) === SyntaxKind.TemplateHead) { + result.finalLexState = EndOfLineState.InTemplateSubstitutionPosition; + } } } @@ -5866,7 +5935,7 @@ module ts { return token >= SyntaxKind.FirstKeyword && token <= SyntaxKind.LastKeyword; } - function classFromKind(token: SyntaxKind) { + function classFromKind(token: SyntaxKind, syntacticClassifierAbsent?: boolean) { if (isKeyword(token)) { return TokenClass.Keyword; } @@ -5892,6 +5961,10 @@ module ts { return TokenClass.Whitespace; case SyntaxKind.Identifier: default: + // Only give a classification if nothing will more accurately classify. + if (syntacticClassifierAbsent && isTemplateLiteralKind(token)) { + return TokenClass.StringLiteral; // should make a TemplateLiteral + } return TokenClass.Identifier; } } From 3429fab6fbdd5fb37975c088b88079a4cd22fb30 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 20 Jan 2015 12:42:03 -0800 Subject: [PATCH 02/17] Fixed issue with the kinds we check. --- src/services/services.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index d585722e7ef..50b852c241b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1143,8 +1143,8 @@ module ts { InMultiLineCommentTrivia, InSingleQuoteStringLiteral, InDoubleQuoteStringLiteral, - InTemplateHeadLiteral, // this could also be a NoSubstitutionTemplateLiteral - InTemplateMiddleLiteral, //this could also be a TemplateTail + InTemplateHeadOrNoSubstitutionTemplate, + InTemplateMiddleOrTail, InTemplateSubstitutionPosition, } @@ -5678,20 +5678,22 @@ module ts { text = "/*\n" + text; offset = 3; break; - case EndOfLineState.InTemplateHeadLiteral: + case EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate: if (syntacticClassifierAbsent) { text = "`\n" + text; offset = 2; } break; - case EndOfLineState.InTemplateMiddleLiteral: + case EndOfLineState.InTemplateMiddleOrTail: if (syntacticClassifierAbsent) { - text = "${\n" + text; - offset = 3; + text = "}\n" + text; + offset = 2; } // fallthrough case EndOfLineState.InTemplateSubstitutionPosition: - templateStack = [SyntaxKind.TemplateHead]; + if (syntacticClassifierAbsent) { + templateStack = [SyntaxKind.TemplateHead]; + } break; } @@ -5847,11 +5849,14 @@ module ts { } else if (isTemplateLiteralKind(token) && syntacticClassifierAbsent) { if (scanner.isUnterminated()) { - if (token === SyntaxKind.TemplateMiddle) { - result.finalLexState = EndOfLineState.InTemplateMiddleLiteral; + if (token === SyntaxKind.TemplateTail) { + result.finalLexState = EndOfLineState.InTemplateMiddleOrTail; + } + else if (token === SyntaxKind.NoSubstitutionTemplateLiteral) { + result.finalLexState = EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate; } else { - result.finalLexState = EndOfLineState.InTemplateHeadLiteral; + Debug.fail("Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + token); } } } From f1f085eda65876cb3d8ae2a57b3ec8a03f86ac7b Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 26 Jan 2015 12:06:01 -0800 Subject: [PATCH 03/17] Addressed CR feedback. --- src/services/services.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 50b852c241b..858a1ac1757 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5620,6 +5620,10 @@ module ts { noRegexTable[SyntaxKind.TrueKeyword] = true; noRegexTable[SyntaxKind.FalseKeyword] = true; + // Just a stack of TemplateHeads and OpenCurlyBraces, used + // to perform rudimentary classification on templates. + var templateStack: SyntaxKind[] = []; + function isAccessibilityModifier(kind: SyntaxKind) { switch (kind) { case SyntaxKind.PublicKeyword: @@ -5658,7 +5662,6 @@ module ts { var offset = 0; var token = SyntaxKind.Unknown; var lastNonTriviaToken = SyntaxKind.Unknown; - var templateStack: SyntaxKind[]; // If we're in a string literal, then prepend: "\ // (and a newline). That way when we lex we'll think we're still in a string literal. @@ -5725,6 +5728,11 @@ module ts { // work well enough in practice. var angleBracketStack = 0; + // Empty out the template stack for reuse. + while (templateStack.length > 0) { + templateStack.pop(); + } + do { token = scanner.scan(); @@ -5767,24 +5775,19 @@ module ts { } } else if (token === SyntaxKind.TemplateHead && syntacticClassifierAbsent) { - if (!templateStack) { - templateStack = [token]; - } - else { - templateStack.push(token); - } + templateStack.push(token); } else if (token === SyntaxKind.OpenBraceToken && syntacticClassifierAbsent) { // If we don't have anything on the template stack, // then we aren't trying to keep track of a previously scanned template head. - if (templateStack && templateStack.length > 0) { + if (templateStack.length > 0) { templateStack.push(token); } } else if (token === SyntaxKind.CloseBraceToken && syntacticClassifierAbsent) { // If we don't have anything on the template stack, // then we aren't trying to keep track of a previously scanned template head. - if (templateStack && templateStack.length > 0) { + if (templateStack.length > 0) { var lastTemplateStackToken = lastOrUndefined(templateStack); if (lastTemplateStackToken === SyntaxKind.TemplateHead) { @@ -5860,7 +5863,7 @@ module ts { } } } - else if (templateStack && templateStack.length > 0 && lastOrUndefined(templateStack) === SyntaxKind.TemplateHead) { + else if (templateStack.length > 0 && lastOrUndefined(templateStack) === SyntaxKind.TemplateHead) { result.finalLexState = EndOfLineState.InTemplateSubstitutionPosition; } } From 3fea0aefbef3ff808de8799bd1a622cd41c08885 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 26 Jan 2015 12:37:03 -0800 Subject: [PATCH 04/17] classifyKeywordsInGenerics -> syntacticClassifierAbsent --- src/services/services.ts | 2 +- src/services/shims.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 858a1ac1757..172fb4ab00e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1171,7 +1171,7 @@ module ts { } export interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; } /** diff --git a/src/services/shims.ts b/src/services/shims.ts index 0f9f1a12cd1..a0eb1cb1ac4 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -165,7 +165,7 @@ module ts { } export interface ClassifierShim extends Shim { - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): string; + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string; } export interface CoreServicesShim extends Shim { From ab79faef85568a9944709c0940c6f484aaa5187c Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 26 Jan 2015 15:41:01 -0800 Subject: [PATCH 05/17] Added tests, fixed order of emptying templateStack, unconditionally perform template classification. --- src/services/services.ts | 43 +++--- .../cases/unittests/services/colorization.ts | 130 ++++++++++++++++-- 2 files changed, 137 insertions(+), 36 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 172fb4ab00e..673748d6969 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5663,6 +5663,11 @@ module ts { var token = SyntaxKind.Unknown; var lastNonTriviaToken = SyntaxKind.Unknown; + // Empty out the template stack for reuse. + while (templateStack.length > 0) { + templateStack.pop(); + } + // If we're in a string literal, then prepend: "\ // (and a newline). That way when we lex we'll think we're still in a string literal. // @@ -5682,21 +5687,15 @@ module ts { offset = 3; break; case EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate: - if (syntacticClassifierAbsent) { - text = "`\n" + text; - offset = 2; - } + text = "`\n" + text; + offset = 2; break; case EndOfLineState.InTemplateMiddleOrTail: - if (syntacticClassifierAbsent) { - text = "}\n" + text; - offset = 2; - } + text = "}\n" + text; + offset = 2; // fallthrough case EndOfLineState.InTemplateSubstitutionPosition: - if (syntacticClassifierAbsent) { - templateStack = [SyntaxKind.TemplateHead]; - } + templateStack.push(SyntaxKind.TemplateHead); break; } @@ -5728,11 +5727,6 @@ module ts { // work well enough in practice. var angleBracketStack = 0; - // Empty out the template stack for reuse. - while (templateStack.length > 0) { - templateStack.pop(); - } - do { token = scanner.scan(); @@ -5774,17 +5768,17 @@ module ts { token = SyntaxKind.Identifier; } } - else if (token === SyntaxKind.TemplateHead && syntacticClassifierAbsent) { + else if (token === SyntaxKind.TemplateHead) { templateStack.push(token); } - else if (token === SyntaxKind.OpenBraceToken && syntacticClassifierAbsent) { + else if (token === SyntaxKind.OpenBraceToken) { // If we don't have anything on the template stack, // then we aren't trying to keep track of a previously scanned template head. if (templateStack.length > 0) { templateStack.push(token); } } - else if (token === SyntaxKind.CloseBraceToken && syntacticClassifierAbsent) { + else if (token === SyntaxKind.CloseBraceToken) { // If we don't have anything on the template stack, // then we aren't trying to keep track of a previously scanned template head. if (templateStack.length > 0) { @@ -5821,7 +5815,7 @@ module ts { var start = scanner.getTokenPos(); var end = scanner.getTextPos(); - addResult(end - start, classFromKind(token, syntacticClassifierAbsent)); + addResult(end - start, classFromKind(token)); if (end >= text.length) { if (token === SyntaxKind.StringLiteral) { @@ -5850,7 +5844,7 @@ module ts { result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; } } - else if (isTemplateLiteralKind(token) && syntacticClassifierAbsent) { + else if (isTemplateLiteralKind(token)) { if (scanner.isUnterminated()) { if (token === SyntaxKind.TemplateTail) { result.finalLexState = EndOfLineState.InTemplateMiddleOrTail; @@ -5943,7 +5937,7 @@ module ts { return token >= SyntaxKind.FirstKeyword && token <= SyntaxKind.LastKeyword; } - function classFromKind(token: SyntaxKind, syntacticClassifierAbsent?: boolean) { + function classFromKind(token: SyntaxKind) { if (isKeyword(token)) { return TokenClass.Keyword; } @@ -5969,9 +5963,8 @@ module ts { return TokenClass.Whitespace; case SyntaxKind.Identifier: default: - // Only give a classification if nothing will more accurately classify. - if (syntacticClassifierAbsent && isTemplateLiteralKind(token)) { - return TokenClass.StringLiteral; // should make a TemplateLiteral + if (isTemplateLiteralKind(token)) { + return TokenClass.StringLiteral; // maybe make a TemplateLiteral } return TokenClass.Identifier; } diff --git a/tests/cases/unittests/services/colorization.ts b/tests/cases/unittests/services/colorization.ts index 01149764305..c834f85806d 100644 --- a/tests/cases/unittests/services/colorization.ts +++ b/tests/cases/unittests/services/colorization.ts @@ -4,6 +4,7 @@ interface ClassificationEntry { value: any; classification: ts.TokenClass; + position?: number; } describe('Colorization', function () { @@ -23,16 +24,23 @@ describe('Colorization', function () { return undefined; } - function punctuation(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Punctuation }; } - function keyword(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Keyword }; } - function operator(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Operator }; } - function comment(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Comment }; } - function whitespace(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Whitespace }; } - function identifier(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Identifier }; } - function numberLiteral(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.NumberLiteral }; } - function stringLiteral(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.StringLiteral }; } - function regExpLiteral(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.RegExpLiteral }; } - function finalEndOfLineState(value: number): ClassificationEntry { return { value: value, classification: undefined }; } + function punctuation(text: string, position?: number) { return createClassification(text, ts.TokenClass.Punctuation, position); } + function keyword(text: string, position?: number) { return createClassification(text, ts.TokenClass.Keyword, position); } + function operator(text: string, position?: number) { return createClassification(text, ts.TokenClass.Operator, position); } + function comment(text: string, position?: number) { return createClassification(text, ts.TokenClass.Comment, position); } + function whitespace(text: string, position?: number) { return createClassification(text, ts.TokenClass.Whitespace, position); } + function identifier(text: string, position?: number) { return createClassification(text, ts.TokenClass.Identifier, position); } + function numberLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.NumberLiteral, position); } + function stringLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.StringLiteral, position); } + function regExpLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.RegExpLiteral, position); } + function finalEndOfLineState(value: number): ClassificationEntry { return { value: value, classification: undefined, position: 0 }; } + function createClassification(text: string, tokenClass: ts.TokenClass, position?: number): ClassificationEntry { + return { + value: text, + classification: tokenClass, + position: position, + }; + } function testLexicalClassification(text: string, initialEndOfLineState: ts.EndOfLineState, ...expectedEntries: ClassificationEntry[]): void { var result = classifier.getClassificationsForLine(text, initialEndOfLineState); @@ -44,7 +52,7 @@ describe('Colorization', function () { assert.equal(result.finalLexState, expectedEntry.value, "final endOfLineState does not match expected."); } else { - var actualEntryPosition = text.indexOf(expectedEntry.value); + var actualEntryPosition = expectedEntry.position !== undefined ? expectedEntry.position : text.indexOf(expectedEntry.value); assert(actualEntryPosition >= 0, "token: '" + expectedEntry.value + "' does not exit in text: '" + text + "'."); var actualEntry = getEntryAtPosistion(result, actualEntryPosition); @@ -254,6 +262,106 @@ describe('Colorization', function () { finalEndOfLineState(ts.EndOfLineState.Start)); }); + it("classifies a single line no substitution template string correctly", () => { + testLexicalClassification("`number number public string`", + ts.EndOfLineState.Start, + stringLiteral("`number number public string`"), + finalEndOfLineState(ts.EndOfLineState.Start)); + }); + it("classifies substitution parts of a template string correctly", () => { + testLexicalClassification("`number '${ 1 + 1 }' string '${ 'hello' }'`", + ts.EndOfLineState.Start, + stringLiteral("`number '${"), + numberLiteral("1"), + operator("+"), + numberLiteral("1"), + stringLiteral("}' string '${"), + stringLiteral("'hello'"), + stringLiteral("}'`"), + finalEndOfLineState(ts.EndOfLineState.Start)); + }); + it("classifies an unterminated no substitution template string correctly", () => { + testLexicalClassification("`hello world", + ts.EndOfLineState.Start, + stringLiteral("`hello world"), + finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate)); + }); + it("classifies the entire line of an unterminated multiline no-substitution/head template", () => { + testLexicalClassification("...", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("..."), + finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate)); + }); + it("classifies the entire line of an unterminated multiline template middle/end",() => { + testLexicalClassification("...", + ts.EndOfLineState.InTemplateMiddleOrTail, + stringLiteral("..."), + finalEndOfLineState(ts.EndOfLineState.InTemplateMiddleOrTail)); + }); + it("classifies a termination of a multiline template head", () => { + testLexicalClassification("...${", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("...${"), + finalEndOfLineState(ts.EndOfLineState.InTemplateSubstitutionPosition)); + }); + it("classifies the termination of a multiline no substitution template", () => { + testLexicalClassification("...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("...`"), + finalEndOfLineState(ts.EndOfLineState.Start)); + }); + it("classifies the substitution parts and middle/tail of a multiline template string", () => { + testLexicalClassification("${ 1 + 1 }...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("${"), + numberLiteral("1"), + operator("+"), + numberLiteral("1"), + stringLiteral("}...`"), + finalEndOfLineState(ts.EndOfLineState.Start)); + }); + it("classifies a template middle and propagates the end of line state",() => { + testLexicalClassification("${ 1 + 1 }...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("${"), + numberLiteral("1"), + operator("+"), + numberLiteral("1"), + stringLiteral("}...`"), + finalEndOfLineState(ts.EndOfLineState.Start)); + }); + it("classifies substitution expressions with curly braces appropriately", () => { + var pos = 0; + var lastLength = 0; + + testLexicalClassification("...${ () => { } } ${ { x: `1` } }...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral(track("...${"), pos), + punctuation(track(" ", "("), pos), + punctuation(track(")"), pos), + punctuation(track(" ", "=>"), pos), + punctuation(track(" ", "{"), pos), + punctuation(track(" ", "}"), pos), + stringLiteral(track(" ", "} ${"), pos), + punctuation(track(" ", "{"), pos), + identifier(track(" ", "x"), pos), + punctuation(track(":"), pos), + stringLiteral(track(" ", "`1`"), pos), + punctuation(track(" ", "}"), pos), + stringLiteral(track(" ", "}...`"), pos), + finalEndOfLineState(ts.EndOfLineState.Start)); + + // Adjusts 'pos' by accounting for the length of each portion of the string, + // but only return the last given string + function track(...vals: string[]): string { + for (var i = 0, n = vals.length; i < n; i++) { + pos += lastLength; + lastLength = vals[i].length; + } + return ts.lastOrUndefined(vals); + } + }); + it("classifies partially written generics correctly.", function () { testLexicalClassification("Foo Date: Mon, 26 Jan 2015 15:43:26 -0800 Subject: [PATCH 06/17] Fixed assertion --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 673748d6969..90227eeb1f7 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5796,7 +5796,7 @@ module ts { } } else { - Debug.assert(token === SyntaxKind.CloseBraceToken, "Should have been an open brace. Was: " + token); + Debug.assert(lastTemplateStackToken === SyntaxKind.OpenBraceToken, "Should have been an open brace. Was: " + token); templateStack.pop(); } } From 15b333e10281fcb3d136b57d80597233154d1742 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 26 Jan 2015 16:06:56 -0800 Subject: [PATCH 07/17] Added comment for 'syntacticClassifierAbsent'. --- src/services/services.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/services.ts b/src/services/services.ts index 90227eeb1f7..39eab2f7e16 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5658,6 +5658,8 @@ module ts { return true; } + // If there is a syntactic classifier ('syntacticClassifierAbsent' is false), + // we will be more conservative in order to avoid conflicting with the syntactic classifier. function getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult { var offset = 0; var token = SyntaxKind.Unknown; From a9df539b7e2ced08f43c848913ae862ef900b16e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 12 Feb 2015 16:37:07 -0800 Subject: [PATCH 08/17] added check that var and let\const cannot share scope, added check that var is not shadowed by the let\const from the inner scope --- src/compiler/binder.ts | 10 ++ src/compiler/checker.ts | 51 ++++++-- .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 4 + ...arationShadowedByVarDeclaration.errors.txt | 12 +- .../letAndVarRedeclaration.errors.txt | 118 ++++++++++++++++++ .../reference/letAndVarRedeclaration.js | 102 +++++++++++++++ .../shadowingViaLocalValue.errors.txt | 30 +++++ .../reference/shadowingViaLocalValue.js | 31 +++++ .../cases/compiler/letAndVarRedeclaration.ts | 53 ++++++++ .../cases/compiler/shadowingViaLocalValue.ts | 14 +++ 11 files changed, 410 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/letAndVarRedeclaration.errors.txt create mode 100644 tests/baselines/reference/letAndVarRedeclaration.js create mode 100644 tests/baselines/reference/shadowingViaLocalValue.errors.txt create mode 100644 tests/baselines/reference/shadowingViaLocalValue.js create mode 100644 tests/cases/compiler/letAndVarRedeclaration.ts create mode 100644 tests/cases/compiler/shadowingViaLocalValue.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c1b9d76f1b5..be9e9a525c0 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -482,6 +482,16 @@ module ts { break; } case SyntaxKind.Block: + // do not treat function block a block-scope container + // all block-scope locals that reside in this block should go to the function locals. + // Otherwise this won't be considered as redeclaration of a block scoped local: + // function foo() { + // let x; + // var x; + // } + // 'var x' will be placed into the function locals and 'let x' - into the locals of the block + bindChildren(node, 0, /*isBlockScopeContainer*/ !isAnyFunction(node.parent)); + break; case SyntaxKind.CatchClause: case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cccd74e3907..91537818175 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8198,19 +8198,26 @@ module ts { } } - function checkCollisionWithConstDeclarations(node: VariableLikeDeclaration) { + function checkVarDeclaredNamesNotShadowed(node: VariableDeclaration | BindingElement) { + // - ScriptBody : StatementList + // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList + // also occurs in the VarDeclaredNames of StatementList. + + // - Block : { StatementList } + // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList + // also occurs in the VarDeclaredNames of StatementList. + // Variable declarations are hoisted to the top of their function scope. They can shadow // block scoped declarations, which bind tighter. this will not be flagged as duplicate definition // by the binder as the declaration scope is different. // A non-initialized declaration is a no-op as the block declaration will resolve before the var // declaration. the problem is if the declaration has an initializer. this will act as a write to the // block declared value. this is fine for let, but not const. - // // Only consider declarations with initializers, uninitialized var declarations will not - // step on a const variable. + // step on a let\const variable. // Do not consider let and const declarations, as duplicate block-scoped declarations - // are handled by the binder. - // We are only looking for var declarations that step on const declarations from a + // are handled by the binder. + // We are only looking for var declarations that step on let\const declarations from a // different scope. e.g.: // var x = 0; // { @@ -8219,11 +8226,33 @@ module ts { // } if (node.initializer && (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) === 0) { var symbol = getSymbolOfNode(node); - if (symbol.flags & SymbolFlags.FunctionScopedVariable) { + if (symbol.flags & (SymbolFlags.FunctionScopedVariable)) { var localDeclarationSymbol = resolveName(node, (node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); - if (localDeclarationSymbol && localDeclarationSymbol !== symbol && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { - if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.Const) { - error(node, Diagnostics.Cannot_redeclare_block_scoped_variable_0, symbolToString(localDeclarationSymbol)); + if (localDeclarationSymbol && + localDeclarationSymbol !== symbol && + localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { + if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & (NodeFlags.Let | NodeFlags.Const)) { + // here we know that function scoped variable is shadowed by block scoped one + // if they are defined in the same scope - binder has already reported redeclaration error + // otherwise if variable has an initializer - show error that initialization will fail + // since LHS will be block scoped name instead of function scoped + + var localVarDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList); + var localContainer = + localVarDeclList.parent.kind === SyntaxKind.VariableStatement && + localVarDeclList.parent.parent; + + // if block scoped variable is defined in the function\module\source file scope + // then since function scoped variable is hoised their names will collide + var namesShareScope = + localContainer && + (localContainer.kind === SyntaxKind.Block && isAnyFunction(localContainer.parent) || + (localContainer.kind === SyntaxKind.ModuleBlock && localContainer.kind === SyntaxKind.ModuleDeclaration) || + localContainer.kind === SyntaxKind.SourceFile); + + if (!namesShareScope) { + error(getErrorSpanForNode(node), Diagnostics.Cannot_initialize_outer_scope_variable_0_when_having_block_scoped_variable_with_the_same_name, symbolToString(localDeclarationSymbol)); + } } } } @@ -8320,7 +8349,9 @@ module ts { if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { // We know we don't have a binding pattern or computed name here checkExportsOnMergedDeclarations(node); - checkCollisionWithConstDeclarations(node); + if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { + checkVarDeclaredNamesNotShadowed(node); + } checkCollisionWithCapturedSuperVariable(node, node.name); checkCollisionWithCapturedThisVariable(node, node.name); checkCollisionWithRequireExportsInGeneratedCode(node, node.name); diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 6c79578e41c..06ee032a498 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -381,6 +381,7 @@ module ts { const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 4087, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." }, Property_0_does_not_exist_on_const_enum_1: { code: 4088, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on 'const' enum '{1}'." }, let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations: { code: 4089, category: DiagnosticCategory.Error, key: "'let' is not allowed to be used as a name in 'let' or 'const' declarations." }, + Cannot_initialize_outer_scope_variable_0_when_having_block_scoped_variable_with_the_same_name: { code: 4090, category: DiagnosticCategory.Error, key: "Cannot initialize outer scope variable '{0}' when having block-scoped variable with the same name." }, The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." }, Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." }, Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 8a5d8d80427..efe2a63f911 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1517,6 +1517,10 @@ "category": "Error", "code": 4089 }, + "Cannot initialize outer scope variable '{0}' when having block-scoped variable with the same name.": { + "category": "Error", + "code": 4090 + }, "The current host does not support the '{0}' option.": { "category": "Error", "code": 5001 diff --git a/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt b/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt index 629cf7f75af..529964a6a85 100644 --- a/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt +++ b/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt @@ -1,6 +1,6 @@ -tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(7,9): error TS2451: Cannot redeclare block-scoped variable 'x'. -tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(15,13): error TS2451: Cannot redeclare block-scoped variable 'y'. -tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS2451: Cannot redeclare block-scoped variable 'z'. +tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(7,9): error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. +tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(15,13): error TS4090: Cannot initialize outer scope variable 'y' when having block-scoped variable with the same name. +tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS4090: Cannot initialize outer scope variable 'z' when having block-scoped variable with the same name. ==== tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts (3 errors) ==== @@ -12,7 +12,7 @@ tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS var x = 0; ~ -!!! error TS2451: Cannot redeclare block-scoped variable 'x'. +!!! error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. } @@ -22,7 +22,7 @@ tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS { var y = 0; ~ -!!! error TS2451: Cannot redeclare block-scoped variable 'y'. +!!! error TS4090: Cannot initialize outer scope variable 'y' when having block-scoped variable with the same name. } } @@ -31,5 +31,5 @@ tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS const z = 0; var z = 0 ~ -!!! error TS2451: Cannot redeclare block-scoped variable 'z'. +!!! error TS4090: Cannot initialize outer scope variable 'z' when having block-scoped variable with the same name. } \ No newline at end of file diff --git a/tests/baselines/reference/letAndVarRedeclaration.errors.txt b/tests/baselines/reference/letAndVarRedeclaration.errors.txt new file mode 100644 index 00000000000..48704f61040 --- /dev/null +++ b/tests/baselines/reference/letAndVarRedeclaration.errors.txt @@ -0,0 +1,118 @@ +tests/cases/compiler/letAndVarRedeclaration.ts(2,5): error TS2451: Cannot redeclare block-scoped variable 'e0'. +tests/cases/compiler/letAndVarRedeclaration.ts(3,5): error TS2451: Cannot redeclare block-scoped variable 'e0'. +tests/cases/compiler/letAndVarRedeclaration.ts(4,10): error TS2451: Cannot redeclare block-scoped variable 'e0'. +tests/cases/compiler/letAndVarRedeclaration.ts(7,9): error TS2451: Cannot redeclare block-scoped variable 'x1'. +tests/cases/compiler/letAndVarRedeclaration.ts(8,9): error TS2451: Cannot redeclare block-scoped variable 'x1'. +tests/cases/compiler/letAndVarRedeclaration.ts(9,14): error TS2451: Cannot redeclare block-scoped variable 'x1'. +tests/cases/compiler/letAndVarRedeclaration.ts(13,9): error TS2451: Cannot redeclare block-scoped variable 'x'. +tests/cases/compiler/letAndVarRedeclaration.ts(15,13): error TS2451: Cannot redeclare block-scoped variable 'x'. +tests/cases/compiler/letAndVarRedeclaration.ts(18,18): error TS2451: Cannot redeclare block-scoped variable 'x'. +tests/cases/compiler/letAndVarRedeclaration.ts(23,9): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/compiler/letAndVarRedeclaration.ts(24,9): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/compiler/letAndVarRedeclaration.ts(25,14): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/compiler/letAndVarRedeclaration.ts(29,9): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/compiler/letAndVarRedeclaration.ts(31,13): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/compiler/letAndVarRedeclaration.ts(34,18): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/compiler/letAndVarRedeclaration.ts(38,5): error TS2451: Cannot redeclare block-scoped variable 'x11'. +tests/cases/compiler/letAndVarRedeclaration.ts(39,10): error TS2451: Cannot redeclare block-scoped variable 'x11'. +tests/cases/compiler/letAndVarRedeclaration.ts(43,9): error TS2451: Cannot redeclare block-scoped variable 'x11'. +tests/cases/compiler/letAndVarRedeclaration.ts(44,14): error TS2451: Cannot redeclare block-scoped variable 'x11'. +tests/cases/compiler/letAndVarRedeclaration.ts(49,9): error TS2451: Cannot redeclare block-scoped variable 'x11'. +tests/cases/compiler/letAndVarRedeclaration.ts(50,14): error TS2451: Cannot redeclare block-scoped variable 'x11'. + + +==== tests/cases/compiler/letAndVarRedeclaration.ts (21 errors) ==== + + let e0 + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'e0'. + var e0; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'e0'. + function e0() { } + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'e0'. + + function f0() { + let x1; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x1'. + var x1; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x1'. + function x1() { } + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x1'. + } + + function f1() { + let x; + ~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x'. + { + var x; + ~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x'. + } + { + function x() { } + ~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x'. + } + } + + module M0 { + let x2; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. + var x2; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. + function x2() { } + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. + } + + module M1 { + let x2; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. + { + var x2; + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. + } + { + function x2() { } + ~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. + } + } + + let x11; + ~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x11'. + for (var x11; ;) { + ~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x11'. + } + + function f2() { + let x11; + ~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x11'. + for (var x11; ;) { + ~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x11'. + } + } + + module M2 { + let x11; + ~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x11'. + for (var x11; ;) { + ~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'x11'. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/letAndVarRedeclaration.js b/tests/baselines/reference/letAndVarRedeclaration.js new file mode 100644 index 00000000000..fd4bfe67cac --- /dev/null +++ b/tests/baselines/reference/letAndVarRedeclaration.js @@ -0,0 +1,102 @@ +//// [letAndVarRedeclaration.ts] + +let e0 +var e0; +function e0() { } + +function f0() { + let x1; + var x1; + function x1() { } +} + +function f1() { + let x; + { + var x; + } + { + function x() { } + } +} + +module M0 { + let x2; + var x2; + function x2() { } +} + +module M1 { + let x2; + { + var x2; + } + { + function x2() { } + } +} + +let x11; +for (var x11; ;) { +} + +function f2() { + let x11; + for (var x11; ;) { + } +} + +module M2 { + let x11; + for (var x11; ;) { + } +} + +//// [letAndVarRedeclaration.js] +let e0; +var e0; +function e0() { } +function f0() { + let x1; + var x1; + function x1() { } +} +function f1() { + let x; + { + var x; + } + { + function x() { } + } +} +var M0; +(function (M0) { + let x2; + var x2; + function x2() { } +})(M0 || (M0 = {})); +var M1; +(function (M1) { + let x2; + { + var x2; + } + { + function x2() { } + } +})(M1 || (M1 = {})); +let x11; +for (var x11;;) { +} +function f2() { + let x11; + for (var x11;;) { + } +} +var M2; +(function (M2) { + let x11; + for (var x11;;) { + } +})(M2 || (M2 = {})); diff --git a/tests/baselines/reference/shadowingViaLocalValue.errors.txt b/tests/baselines/reference/shadowingViaLocalValue.errors.txt new file mode 100644 index 00000000000..a4a8d9a05d2 --- /dev/null +++ b/tests/baselines/reference/shadowingViaLocalValue.errors.txt @@ -0,0 +1,30 @@ +tests/cases/compiler/shadowingViaLocalValue.ts(2,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/shadowingViaLocalValue.ts(4,13): error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. +tests/cases/compiler/shadowingViaLocalValue.ts(9,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/shadowingViaLocalValue.ts(11,18): error TS4090: Cannot initialize outer scope variable 'x1' when having block-scoped variable with the same name. + + +==== tests/cases/compiler/shadowingViaLocalValue.ts (4 errors) ==== + { + let x; + ~~~ +!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. + { + var x = 1; + ~ +!!! error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. + } + } + + { + let x1; + ~~~ +!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. + { + for (var x1 = 0; ;); + ~~ +!!! error TS4090: Cannot initialize outer scope variable 'x1' when having block-scoped variable with the same name. + } + } + + \ No newline at end of file diff --git a/tests/baselines/reference/shadowingViaLocalValue.js b/tests/baselines/reference/shadowingViaLocalValue.js new file mode 100644 index 00000000000..f99a209f0de --- /dev/null +++ b/tests/baselines/reference/shadowingViaLocalValue.js @@ -0,0 +1,31 @@ +//// [shadowingViaLocalValue.ts] +{ + let x; + { + var x = 1; + } +} + +{ + let x1; + { + for (var x1 = 0; ;); + } +} + + + +//// [shadowingViaLocalValue.js] +{ + let x; + { + var x = 1; + } +} +{ + let x1; + { + for (var x1 = 0;;) + ; + } +} diff --git a/tests/cases/compiler/letAndVarRedeclaration.ts b/tests/cases/compiler/letAndVarRedeclaration.ts new file mode 100644 index 00000000000..1f901ded520 --- /dev/null +++ b/tests/cases/compiler/letAndVarRedeclaration.ts @@ -0,0 +1,53 @@ +// @target: es6 + +let e0 +var e0; +function e0() { } + +function f0() { + let x1; + var x1; + function x1() { } +} + +function f1() { + let x; + { + var x; + } + { + function x() { } + } +} + +module M0 { + let x2; + var x2; + function x2() { } +} + +module M1 { + let x2; + { + var x2; + } + { + function x2() { } + } +} + +let x11; +for (var x11; ;) { +} + +function f2() { + let x11; + for (var x11; ;) { + } +} + +module M2 { + let x11; + for (var x11; ;) { + } +} \ No newline at end of file diff --git a/tests/cases/compiler/shadowingViaLocalValue.ts b/tests/cases/compiler/shadowingViaLocalValue.ts new file mode 100644 index 00000000000..72bc0f0e33e --- /dev/null +++ b/tests/cases/compiler/shadowingViaLocalValue.ts @@ -0,0 +1,14 @@ +{ + let x; + { + var x = 1; + } +} + +{ + let x1; + { + for (var x1 = 0; ;); + } +} + From 07dbd30ba167f571e8c6f3d81ddb4b4be975be04 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 12 Feb 2015 16:40:06 -0800 Subject: [PATCH 09/17] update comment text --- 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 91537818175..6d1be6b4fa5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8241,9 +8241,9 @@ module ts { var localContainer = localVarDeclList.parent.kind === SyntaxKind.VariableStatement && localVarDeclList.parent.parent; - - // if block scoped variable is defined in the function\module\source file scope - // then since function scoped variable is hoised their names will collide + + // names of block-scoped and function scoped variables can collide only + // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) var namesShareScope = localContainer && (localContainer.kind === SyntaxKind.Block && isAnyFunction(localContainer.parent) || From 65e23b1e60699ed22add237a75ada0e3589f4aa2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 12 Feb 2015 16:46:25 -0800 Subject: [PATCH 10/17] Added API baseline changes. --- tests/baselines/reference/APISample_compile.js | 5 ++++- tests/baselines/reference/APISample_compile.types | 15 ++++++++++++--- tests/baselines/reference/APISample_linter.js | 5 ++++- tests/baselines/reference/APISample_linter.types | 15 ++++++++++++--- tests/baselines/reference/APISample_transform.js | 5 ++++- .../baselines/reference/APISample_transform.types | 15 ++++++++++++--- tests/baselines/reference/APISample_watcher.js | 5 ++++- tests/baselines/reference/APISample_watcher.types | 15 ++++++++++++--- 8 files changed, 64 insertions(+), 16 deletions(-) diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 9a44ae12df0..98b80ebc868 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1741,6 +1741,9 @@ declare module "typescript" { InMultiLineCommentTrivia = 1, InSingleQuoteStringLiteral = 2, InDoubleQuoteStringLiteral = 3, + InTemplateHeadOrNoSubstitutionTemplate = 4, + InTemplateMiddleOrTail = 5, + InTemplateSubstitutionPosition = 6, } enum TokenClass { Punctuation = 0, @@ -1762,7 +1765,7 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 69458320236..77958b6b16a 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -5539,6 +5539,15 @@ declare module "typescript" { InDoubleQuoteStringLiteral = 3, >InDoubleQuoteStringLiteral : EndOfLineState + + InTemplateHeadOrNoSubstitutionTemplate = 4, +>InTemplateHeadOrNoSubstitutionTemplate : EndOfLineState + + InTemplateMiddleOrTail = 5, +>InTemplateMiddleOrTail : EndOfLineState + + InTemplateSubstitutionPosition = 6, +>InTemplateSubstitutionPosition : EndOfLineState } enum TokenClass { >TokenClass : TokenClass @@ -5594,12 +5603,12 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean) => ClassificationResult + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState ->classifyKeywordsInGenerics : boolean +>syntacticClassifierAbsent : boolean >ClassificationResult : ClassificationResult } /** diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 5413cdb8a78..f22532d353d 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1772,6 +1772,9 @@ declare module "typescript" { InMultiLineCommentTrivia = 1, InSingleQuoteStringLiteral = 2, InDoubleQuoteStringLiteral = 3, + InTemplateHeadOrNoSubstitutionTemplate = 4, + InTemplateMiddleOrTail = 5, + InTemplateSubstitutionPosition = 6, } enum TokenClass { Punctuation = 0, @@ -1793,7 +1796,7 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 55613f8d3e3..09b242ac043 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -5683,6 +5683,15 @@ declare module "typescript" { InDoubleQuoteStringLiteral = 3, >InDoubleQuoteStringLiteral : EndOfLineState + + InTemplateHeadOrNoSubstitutionTemplate = 4, +>InTemplateHeadOrNoSubstitutionTemplate : EndOfLineState + + InTemplateMiddleOrTail = 5, +>InTemplateMiddleOrTail : EndOfLineState + + InTemplateSubstitutionPosition = 6, +>InTemplateSubstitutionPosition : EndOfLineState } enum TokenClass { >TokenClass : TokenClass @@ -5738,12 +5747,12 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean) => ClassificationResult + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState ->classifyKeywordsInGenerics : boolean +>syntacticClassifierAbsent : boolean >ClassificationResult : ClassificationResult } /** diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 13ec31cd7d2..56d7e7db5bc 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1773,6 +1773,9 @@ declare module "typescript" { InMultiLineCommentTrivia = 1, InSingleQuoteStringLiteral = 2, InDoubleQuoteStringLiteral = 3, + InTemplateHeadOrNoSubstitutionTemplate = 4, + InTemplateMiddleOrTail = 5, + InTemplateSubstitutionPosition = 6, } enum TokenClass { Punctuation = 0, @@ -1794,7 +1797,7 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index a8ba6e9f521..ad9623c570e 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -5635,6 +5635,15 @@ declare module "typescript" { InDoubleQuoteStringLiteral = 3, >InDoubleQuoteStringLiteral : EndOfLineState + + InTemplateHeadOrNoSubstitutionTemplate = 4, +>InTemplateHeadOrNoSubstitutionTemplate : EndOfLineState + + InTemplateMiddleOrTail = 5, +>InTemplateMiddleOrTail : EndOfLineState + + InTemplateSubstitutionPosition = 6, +>InTemplateSubstitutionPosition : EndOfLineState } enum TokenClass { >TokenClass : TokenClass @@ -5690,12 +5699,12 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean) => ClassificationResult + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState ->classifyKeywordsInGenerics : boolean +>syntacticClassifierAbsent : boolean >ClassificationResult : ClassificationResult } /** diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 5c3f944faf1..f03a36cfc2e 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1810,6 +1810,9 @@ declare module "typescript" { InMultiLineCommentTrivia = 1, InSingleQuoteStringLiteral = 2, InDoubleQuoteStringLiteral = 3, + InTemplateHeadOrNoSubstitutionTemplate = 4, + InTemplateMiddleOrTail = 5, + InTemplateSubstitutionPosition = 6, } enum TokenClass { Punctuation = 0, @@ -1831,7 +1834,7 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 54304c2e1b9..41f6fd1ced6 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -5808,6 +5808,15 @@ declare module "typescript" { InDoubleQuoteStringLiteral = 3, >InDoubleQuoteStringLiteral : EndOfLineState + + InTemplateHeadOrNoSubstitutionTemplate = 4, +>InTemplateHeadOrNoSubstitutionTemplate : EndOfLineState + + InTemplateMiddleOrTail = 5, +>InTemplateMiddleOrTail : EndOfLineState + + InTemplateSubstitutionPosition = 6, +>InTemplateSubstitutionPosition : EndOfLineState } enum TokenClass { >TokenClass : TokenClass @@ -5863,12 +5872,12 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean) => ClassificationResult + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState ->classifyKeywordsInGenerics : boolean +>syntacticClassifierAbsent : boolean >ClassificationResult : ClassificationResult } /** From be40cac7fdb418d772dd636560ecb526dd98c253 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 12 Feb 2015 17:25:57 -0800 Subject: [PATCH 11/17] Don't check invariants when running RWC tests. It adds too much running time. --- src/harness/harness.ts | 15 +++++++++------ src/harness/rwcRunner.ts | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 534bf85d119..86a68af1145 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -795,9 +795,12 @@ module Harness { } } - export function createSourceFileAndAssertInvariants(fileName: string, sourceText: string, languageVersion: ts.ScriptTarget) { - var result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ true); - Utils.assertInvariants(result, /*parent:*/ undefined); + export function createSourceFileAndAssertInvariants(fileName: string, sourceText: string, languageVersion: ts.ScriptTarget, assertInvariants = true) { + // Only set the parent nodes if we're asserting invariants. We don't need them otherwise. + var result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ assertInvariants); + if (assertInvariants) { + Utils.assertInvariants(result, /*parent:*/ undefined); + } return result; } @@ -805,7 +808,6 @@ module Harness { export var defaultLibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + 'lib.core.d.ts'), /*languageVersion*/ ts.ScriptTarget.Latest); export var defaultES6LibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + 'lib.core.es6.d.ts'), /*languageVersion*/ ts.ScriptTarget.Latest); - // Cache these between executions so we don't have to re-parse them for every test export var fourslashFileName = 'fourslash.ts'; export var fourslashSourceFile: ts.SourceFile; @@ -926,7 +928,8 @@ module Harness { settingsCallback?: (settings: ts.CompilerOptions) => void, options?: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory?: string) { + currentDirectory?: string, + assertInvariants = true) { options = options || { noResolve: false }; options.target = options.target || ts.ScriptTarget.ES3; @@ -1074,7 +1077,7 @@ module Harness { var register = (file: { unitName: string; content: string; }) => { if (file.content !== undefined) { var fileName = ts.normalizeSlashes(file.unitName); - filemap[getCanonicalFileName(fileName)] = createSourceFileAndAssertInvariants(fileName, file.content, options.target); + filemap[getCanonicalFileName(fileName)] = createSourceFileAndAssertInvariants(fileName, file.content, options.target, assertInvariants); } }; inputFiles.forEach(register); diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index b66322f8390..c1c3251cf02 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -90,7 +90,8 @@ module RWC { /*settingsCallback*/ undefined, opts.options, // Since all Rwc json file specified current directory in its json file, we need to pass this information to compilerHost // so that when the host is asked for current directory, it should give the value from json rather than from process - currentDirectory); + currentDirectory, + /*assertInvariants:*/ false); }); function getHarnessCompilerInputUnit(fileName: string) { From e5d80db72c500eac340bae21a82d8f9bfc2330e3 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Feb 2015 10:04:44 -0800 Subject: [PATCH 12/17] addressed PR feedback --- 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 6d1be6b4fa5..41514cc01a9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8216,7 +8216,7 @@ module ts { // Only consider declarations with initializers, uninitialized var declarations will not // step on a let\const variable. // Do not consider let and const declarations, as duplicate block-scoped declarations - // are handled by the binder. + // are handled by the binder. // We are only looking for var declarations that step on let\const declarations from a // different scope. e.g.: // var x = 0; @@ -8226,12 +8226,12 @@ module ts { // } if (node.initializer && (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) === 0) { var symbol = getSymbolOfNode(node); - if (symbol.flags & (SymbolFlags.FunctionScopedVariable)) { + if (symbol.flags & SymbolFlags.FunctionScopedVariable) { var localDeclarationSymbol = resolveName(node, (node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); if (localDeclarationSymbol && localDeclarationSymbol !== symbol && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { - if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & (NodeFlags.Let | NodeFlags.Const)) { + if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { // here we know that function scoped variable is shadowed by block scoped one // if they are defined in the same scope - binder has already reported redeclaration error // otherwise if variable has an initializer - show error that initialization will fail From 1dca5620f52d13af066187cd39357cdfcc9a6123 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 13 Feb 2015 12:56:21 -0800 Subject: [PATCH 13/17] Addressed CR feedback. --- src/services/services.ts | 45 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 39eab2f7e16..0a901f0df0b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1171,7 +1171,26 @@ module ts { } export interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; } /** @@ -5620,8 +5639,26 @@ module ts { noRegexTable[SyntaxKind.TrueKeyword] = true; noRegexTable[SyntaxKind.FalseKeyword] = true; - // Just a stack of TemplateHeads and OpenCurlyBraces, used - // to perform rudimentary classification on templates. + // Just a stack of TemplateHeads and OpenCurlyBraces, used to perform rudimentary (inexact) + // classification on template strings. Because of the context free nature of templates, + // the only precise way to classify a template portion would be by propagating the stack across + // lines, just as we do with the end-of-line state. However, this is a burden for implementers, + // and the behavior is entirely subsumed by the syntactic classifier anyway, so we instead + // flatten any nesting when the template stack is non-empty and encode it in the end-of-line state. + // Situations in which this fails are + // 1) When template strings are nested across different lines: + // `hello ${ `world + // ` }` + // + // Where on the second line, you will get the closing of a template, + // a closing curly, and a new template. + // + // 2) When substitution expressions have curly braces and the curly brace falls on the next line: + // `hello ${ () => { + // return "world" } } ` + // + // Where on the second line, you will get the 'return' keyword, + // a string literal, and a template end consisting of '} } `'. var templateStack: SyntaxKind[] = []; function isAccessibilityModifier(kind: SyntaxKind) { @@ -5966,7 +6003,7 @@ module ts { case SyntaxKind.Identifier: default: if (isTemplateLiteralKind(token)) { - return TokenClass.StringLiteral; // maybe make a TemplateLiteral + return TokenClass.StringLiteral; } return TokenClass.Identifier; } From 3d26fbc4d4af904df0c29a5e269753aa0122cff0 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Feb 2015 13:12:51 -0800 Subject: [PATCH 14/17] adjust error message text based on PR feedback --- src/compiler/checker.ts | 33 +++++++++---------- .../diagnosticInformationMap.generated.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- ...arationShadowedByVarDeclaration.errors.txt | 12 +++---- .../shadowingViaLocalValue.errors.txt | 8 ++--- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 41514cc01a9..239812a9de5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8214,15 +8214,14 @@ module ts { // declaration. the problem is if the declaration has an initializer. this will act as a write to the // block declared value. this is fine for let, but not const. // Only consider declarations with initializers, uninitialized var declarations will not - // step on a let\const variable. + // step on a let/const variable. // Do not consider let and const declarations, as duplicate block-scoped declarations // are handled by the binder. // We are only looking for var declarations that step on let\const declarations from a // different scope. e.g.: - // var x = 0; // { - // const x = 0; - // var x = 0; + // const x = 0; // localDeclarationSymbol obtained after name resolution will correspond to this declaration + // var x = 0; // symbol for this declaration will be 'symbol' // } if (node.initializer && (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) === 0) { var symbol = getSymbolOfNode(node); @@ -8232,26 +8231,26 @@ module ts { localDeclarationSymbol !== symbol && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { - // here we know that function scoped variable is shadowed by block scoped one - // if they are defined in the same scope - binder has already reported redeclaration error - // otherwise if variable has an initializer - show error that initialization will fail - // since LHS will be block scoped name instead of function scoped - var localVarDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList); - var localContainer = - localVarDeclList.parent.kind === SyntaxKind.VariableStatement && - localVarDeclList.parent.parent; + var varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList); + var container = + varDeclList.parent.kind === SyntaxKind.VariableStatement && + varDeclList.parent.parent; // names of block-scoped and function scoped variables can collide only // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) var namesShareScope = - localContainer && - (localContainer.kind === SyntaxKind.Block && isAnyFunction(localContainer.parent) || - (localContainer.kind === SyntaxKind.ModuleBlock && localContainer.kind === SyntaxKind.ModuleDeclaration) || - localContainer.kind === SyntaxKind.SourceFile); + container && + (container.kind === SyntaxKind.Block && isAnyFunction(container.parent) || + (container.kind === SyntaxKind.ModuleBlock && container.kind === SyntaxKind.ModuleDeclaration) || + container.kind === SyntaxKind.SourceFile); + // here we know that function scoped variable is shadowed by block scoped one + // if they are defined in the same scope - binder has already reported redeclaration error + // otherwise if variable has an initializer - show error that initialization will fail + // since LHS will be block scoped name instead of function scoped if (!namesShareScope) { - error(getErrorSpanForNode(node), Diagnostics.Cannot_initialize_outer_scope_variable_0_when_having_block_scoped_variable_with_the_same_name, symbolToString(localDeclarationSymbol)); + error(getErrorSpanForNode(node), Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, symbolToString(localDeclarationSymbol)); } } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 06ee032a498..c6061e3570a 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -381,7 +381,7 @@ module ts { const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 4087, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." }, Property_0_does_not_exist_on_const_enum_1: { code: 4088, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on 'const' enum '{1}'." }, let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations: { code: 4089, category: DiagnosticCategory.Error, key: "'let' is not allowed to be used as a name in 'let' or 'const' declarations." }, - Cannot_initialize_outer_scope_variable_0_when_having_block_scoped_variable_with_the_same_name: { code: 4090, category: DiagnosticCategory.Error, key: "Cannot initialize outer scope variable '{0}' when having block-scoped variable with the same name." }, + Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1: { code: 4090, category: DiagnosticCategory.Error, key: "Cannot initialize outer scoped variable '{0}' in the same scope as block scoped declaration '{1}'." }, The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." }, Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." }, Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index efe2a63f911..fdeec58a705 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1517,7 +1517,7 @@ "category": "Error", "code": 4089 }, - "Cannot initialize outer scope variable '{0}' when having block-scoped variable with the same name.": { + "Cannot initialize outer scoped variable '{0}' in the same scope as block scoped declaration '{1}'.": { "category": "Error", "code": 4090 }, diff --git a/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt b/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt index 529964a6a85..99c02d87f45 100644 --- a/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt +++ b/tests/baselines/reference/constDeclarationShadowedByVarDeclaration.errors.txt @@ -1,6 +1,6 @@ -tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(7,9): error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. -tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(15,13): error TS4090: Cannot initialize outer scope variable 'y' when having block-scoped variable with the same name. -tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS4090: Cannot initialize outer scope variable 'z' when having block-scoped variable with the same name. +tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(7,9): error TS4090: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'. +tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(15,13): error TS4090: Cannot initialize outer scoped variable 'y' in the same scope as block scoped declaration 'y'. +tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS4090: Cannot initialize outer scoped variable 'z' in the same scope as block scoped declaration 'z'. ==== tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts (3 errors) ==== @@ -12,7 +12,7 @@ tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS var x = 0; ~ -!!! error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. +!!! error TS4090: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'. } @@ -22,7 +22,7 @@ tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS { var y = 0; ~ -!!! error TS4090: Cannot initialize outer scope variable 'y' when having block-scoped variable with the same name. +!!! error TS4090: Cannot initialize outer scoped variable 'y' in the same scope as block scoped declaration 'y'. } } @@ -31,5 +31,5 @@ tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS const z = 0; var z = 0 ~ -!!! error TS4090: Cannot initialize outer scope variable 'z' when having block-scoped variable with the same name. +!!! error TS4090: Cannot initialize outer scoped variable 'z' in the same scope as block scoped declaration 'z'. } \ No newline at end of file diff --git a/tests/baselines/reference/shadowingViaLocalValue.errors.txt b/tests/baselines/reference/shadowingViaLocalValue.errors.txt index a4a8d9a05d2..2a585ba8b7d 100644 --- a/tests/baselines/reference/shadowingViaLocalValue.errors.txt +++ b/tests/baselines/reference/shadowingViaLocalValue.errors.txt @@ -1,7 +1,7 @@ tests/cases/compiler/shadowingViaLocalValue.ts(2,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/shadowingViaLocalValue.ts(4,13): error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. +tests/cases/compiler/shadowingViaLocalValue.ts(4,13): error TS4090: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'. tests/cases/compiler/shadowingViaLocalValue.ts(9,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/shadowingViaLocalValue.ts(11,18): error TS4090: Cannot initialize outer scope variable 'x1' when having block-scoped variable with the same name. +tests/cases/compiler/shadowingViaLocalValue.ts(11,18): error TS4090: Cannot initialize outer scoped variable 'x1' in the same scope as block scoped declaration 'x1'. ==== tests/cases/compiler/shadowingViaLocalValue.ts (4 errors) ==== @@ -12,7 +12,7 @@ tests/cases/compiler/shadowingViaLocalValue.ts(11,18): error TS4090: Cannot init { var x = 1; ~ -!!! error TS4090: Cannot initialize outer scope variable 'x' when having block-scoped variable with the same name. +!!! error TS4090: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'. } } @@ -23,7 +23,7 @@ tests/cases/compiler/shadowingViaLocalValue.ts(11,18): error TS4090: Cannot init { for (var x1 = 0; ;); ~~ -!!! error TS4090: Cannot initialize outer scope variable 'x1' when having block-scoped variable with the same name. +!!! error TS4090: Cannot initialize outer scoped variable 'x1' in the same scope as block scoped declaration 'x1'. } } From 941728de074a93488d8d7d6bebd3725d5276f205 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Feb 2015 13:14:47 -0800 Subject: [PATCH 15/17] pass missing argument to error message --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 239812a9de5..b9f8857cb23 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8250,7 +8250,8 @@ module ts { // otherwise if variable has an initializer - show error that initialization will fail // since LHS will be block scoped name instead of function scoped if (!namesShareScope) { - error(getErrorSpanForNode(node), Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, symbolToString(localDeclarationSymbol)); + var name = symbolToString(localDeclarationSymbol); + error(getErrorSpanForNode(node), Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name); } } } From a1b90f0e323a93de4e28f2bdcab3b4e15cb0593d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 13 Feb 2015 13:33:12 -0800 Subject: [PATCH 16/17] Added baselines. --- .../baselines/reference/APISample_compile.js | 21 ++++++++++++++++- .../reference/APISample_compile.types | 23 +++++++++++++++++-- tests/baselines/reference/APISample_linter.js | 21 ++++++++++++++++- .../reference/APISample_linter.types | 23 +++++++++++++++++-- .../reference/APISample_transform.js | 21 ++++++++++++++++- .../reference/APISample_transform.types | 23 +++++++++++++++++-- .../baselines/reference/APISample_watcher.js | 21 ++++++++++++++++- .../reference/APISample_watcher.types | 23 +++++++++++++++++-- 8 files changed, 164 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 98b80ebc868..b91a706aa45 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1765,7 +1765,26 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 77958b6b16a..ae53c666807 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -5603,8 +5603,27 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index f22532d353d..68c13edb7db 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1796,7 +1796,26 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 09b242ac043..0c153e7b1dc 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -5747,8 +5747,27 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 56d7e7db5bc..0e80f6b55b9 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1797,7 +1797,26 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index ad9623c570e..0c201b0a5fd 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -5699,8 +5699,27 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index f03a36cfc2e..27a2ce5e415 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1834,7 +1834,26 @@ declare module "typescript" { classification: TokenClass; } interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; } /** * The document registry represents a store of SourceFile objects that can be shared between diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 41f6fd1ced6..4e137cae59d 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -5872,8 +5872,27 @@ declare module "typescript" { interface Classifier { >Classifier : Classifier - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): ClassificationResult; ->getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean) => ClassificationResult + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; +>getClassificationsForLine : (text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean) => ClassificationResult >text : string >lexState : EndOfLineState >EndOfLineState : EndOfLineState From 91a39dd000844b4171fba073cc09adf4203fa0f2 Mon Sep 17 00:00:00 2001 From: Yui T Date: Fri, 13 Feb 2015 13:42:17 -0800 Subject: [PATCH 17/17] Fix time measurement --- src/compiler/tsc.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 4bcd0856ca8..3f7e6362e19 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -332,7 +332,7 @@ module ts { var program = createProgram(fileNames, compilerOptions, compilerHost); var exitStatus = compileProgram(); - var end = start - new Date().getTime(); + var end = new Date().getTime() - start; if (compilerOptions.listFiles) { forEach(program.getSourceFiles(), file => { @@ -357,7 +357,7 @@ module ts { reportTimeStatistic("Bind time", ts.bindTime); reportTimeStatistic("Check time", ts.checkTime); reportTimeStatistic("Emit time", ts.emitTime); - reportTimeStatistic("Total time", start - end); + reportTimeStatistic("Total time", end); } return { program, exitStatus };