From 171a5f8098831990e8829f5ced2b3cc8827cbea0 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 12 Mar 2015 10:58:16 -0700 Subject: [PATCH 1/3] correctly parse destructuring in let outside of strict mode --- src/compiler/parser.ts | 9 +++++++-- tests/baselines/reference/letInNonStrictMode.js | 11 +++++++++++ tests/baselines/reference/letInNonStrictMode.types | 11 +++++++++++ tests/cases/compiler/letInNonStrictMode.ts | 2 ++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/letInNonStrictMode.js create mode 100644 tests/baselines/reference/letInNonStrictMode.types create mode 100644 tests/cases/compiler/letInNonStrictMode.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6e444eb23c7..7656e2eb2c9 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2975,6 +2975,11 @@ module ts { return !scanner.hasPrecedingLineBreak() && isIdentifier() } + function netTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken) + } + function parseYieldExpression(): YieldExpression { var node = createNode(SyntaxKind.YieldExpression); @@ -4873,9 +4878,9 @@ module ts { } function isLetDeclaration() { - // It is let declaration if in strict mode or next token is identifier on same line. + // It is let declaration if in strict mode or next token is identifier\open brace\open curly on same line. // otherwise it needs to be treated like identifier - return inStrictModeContext() || lookAhead(nextTokenIsIdentifierOnSameLine); + return inStrictModeContext() || lookAhead(netTokenIsIdentifierOrStartOfDestructuringOnTheSameLine); } function isDeclarationStart(): boolean { diff --git a/tests/baselines/reference/letInNonStrictMode.js b/tests/baselines/reference/letInNonStrictMode.js new file mode 100644 index 00000000000..af21ce3281c --- /dev/null +++ b/tests/baselines/reference/letInNonStrictMode.js @@ -0,0 +1,11 @@ +//// [letInNonStrictMode.ts] +let [x] = [1]; +let {a: y} = {a: 1}; + +//// [letInNonStrictMode.js] +var x = ([ + 1 +])[0]; +var y = ({ + a: 1 +}).a; diff --git a/tests/baselines/reference/letInNonStrictMode.types b/tests/baselines/reference/letInNonStrictMode.types new file mode 100644 index 00000000000..4f2cbe4a703 --- /dev/null +++ b/tests/baselines/reference/letInNonStrictMode.types @@ -0,0 +1,11 @@ +=== tests/cases/compiler/letInNonStrictMode.ts === +let [x] = [1]; +>x : number +>[1] : [number] + +let {a: y} = {a: 1}; +>a : unknown +>y : number +>{a: 1} : { a: number; } +>a : number + diff --git a/tests/cases/compiler/letInNonStrictMode.ts b/tests/cases/compiler/letInNonStrictMode.ts new file mode 100644 index 00000000000..576246e76a1 --- /dev/null +++ b/tests/cases/compiler/letInNonStrictMode.ts @@ -0,0 +1,2 @@ +let [x] = [1]; +let {a: y} = {a: 1}; \ No newline at end of file From 64fa7fbecbede0b33acdff69cb63e7425ff6c23b Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Mar 2015 11:52:14 -0700 Subject: [PATCH 2/3] use Value meaning as a filter when resolving names to prevent skipping other value in favor of block-scoped variables --- src/compiler/checker.ts | 2 +- .../letConstMatchingParameterNames.js | 28 ++++++++++++++ .../letConstMatchingParameterNames.types | 37 +++++++++++++++++++ .../letConstMatchingParameterNames.ts | 15 ++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/letConstMatchingParameterNames.js create mode 100644 tests/baselines/reference/letConstMatchingParameterNames.types create mode 100644 tests/cases/compiler/letConstMatchingParameterNames.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1500a47f197..782ffccc0ed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11072,7 +11072,7 @@ module ts { var symbol = declarationSymbol || getNodeLinks(n).resolvedSymbol || - resolveName(n, n.text, SymbolFlags.BlockScopedVariable | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + resolveName(n, n.text, SymbolFlags.Value | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); var isLetOrConst = symbol && diff --git a/tests/baselines/reference/letConstMatchingParameterNames.js b/tests/baselines/reference/letConstMatchingParameterNames.js new file mode 100644 index 00000000000..a11405b9f83 --- /dev/null +++ b/tests/baselines/reference/letConstMatchingParameterNames.js @@ -0,0 +1,28 @@ +//// [letConstMatchingParameterNames.ts] +let parent = true; +const parent2 = true; +declare function use(a: any); + +function a() { + + let parent = 1; + const parent2 = 2; + + function b(parent: string, parent2: number) { + use(parent); + use(parent2); + } +} + + +//// [letConstMatchingParameterNames.js] +var parent = true; +var parent2 = true; +function a() { + var _parent = 1; + var _parent2 = 2; + function b(parent, parent2) { + use(parent); + use(parent2); + } +} diff --git a/tests/baselines/reference/letConstMatchingParameterNames.types b/tests/baselines/reference/letConstMatchingParameterNames.types new file mode 100644 index 00000000000..66fccc637df --- /dev/null +++ b/tests/baselines/reference/letConstMatchingParameterNames.types @@ -0,0 +1,37 @@ +=== tests/cases/compiler/letConstMatchingParameterNames.ts === +let parent = true; +>parent : boolean + +const parent2 = true; +>parent2 : boolean + +declare function use(a: any); +>use : (a: any) => any +>a : any + +function a() { +>a : () => void + + let parent = 1; +>parent : number + + const parent2 = 2; +>parent2 : number + + function b(parent: string, parent2: number) { +>b : (parent: string, parent2: number) => void +>parent : string +>parent2 : number + + use(parent); +>use(parent) : any +>use : (a: any) => any +>parent : string + + use(parent2); +>use(parent2) : any +>use : (a: any) => any +>parent2 : number + } +} + diff --git a/tests/cases/compiler/letConstMatchingParameterNames.ts b/tests/cases/compiler/letConstMatchingParameterNames.ts new file mode 100644 index 00000000000..e749912ad82 --- /dev/null +++ b/tests/cases/compiler/letConstMatchingParameterNames.ts @@ -0,0 +1,15 @@ +// @target: es5 +let parent = true; +const parent2 = true; +declare function use(a: any); + +function a() { + + let parent = 1; + const parent2 = 2; + + function b(parent: string, parent2: number) { + use(parent); + use(parent2); + } +} From e46442f45f99f3277d6e2fc222402c5051379c6f Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Mar 2015 12:08:58 -0700 Subject: [PATCH 3/3] addressed PR feedback: fixed typo in function name --- src/compiler/parser.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7656e2eb2c9..2620c23398b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2975,9 +2975,10 @@ module ts { return !scanner.hasPrecedingLineBreak() && isIdentifier() } - function netTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() { + function nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() { nextToken(); - return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken) + return !scanner.hasPrecedingLineBreak() && + (isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken); } function parseYieldExpression(): YieldExpression { @@ -4878,9 +4879,9 @@ module ts { } function isLetDeclaration() { - // It is let declaration if in strict mode or next token is identifier\open brace\open curly on same line. + // It is let declaration if in strict mode or next token is identifier\open bracket\open curly on same line. // otherwise it needs to be treated like identifier - return inStrictModeContext() || lookAhead(netTokenIsIdentifierOrStartOfDestructuringOnTheSameLine); + return inStrictModeContext() || lookAhead(nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine); } function isDeclarationStart(): boolean {