diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3a6100bbe6b..c6ae2972b30 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3221,30 +3221,44 @@ module ts { } } - // If we had "(" followed by "{" or "[", this could be the start of a binding pattern. - let possiblyInArrayBindingPattern = false; - let possiblyInObjectBindingPattern = false; - while (second === SyntaxKind.OpenBraceToken || second === SyntaxKind.OpenBracketToken) { - possiblyInObjectBindingPattern = second === SyntaxKind.OpenBraceToken; - possiblyInArrayBindingPattern = second === SyntaxKind.OpenBracketToken; - second = nextToken(); - } - - if (possiblyInArrayBindingPattern) { - // If we are possibly in an array binding pattern, skip empty elements - while (second === SyntaxKind.CommaToken) { - second = nextToken(); + // If encounter "([", this could be the start of an array binding pattern. + // Examples: + // ([ x ]) => { } + // ([ x ]) + if (second === SyntaxKind.OpenBracketToken) { + // If the next token is not ",", "...", "[", "{", or an identifier, then this could either be + // an arrow function with an array binding pattern or a parenthesized array literal expression. + // Otherwise, it cannot be an array binding pattern. + let third = nextToken(); + if (isIdentifierOrPattern() || third === SyntaxKind.CommaToken || third === SyntaxKind.DotDotDotToken) { + return Tristate.Unknown; } + + return Tristate.False; } - // Simple case: "(..." or "([...", but not "({..." + // If we encounter "({", this could be the start of an object binding pattern. + // Examples: + // ({ x }) => { } + // ({ x }) + // ({ *x() { }) + if (second === SyntaxKind.OpenBraceToken) { + // If we encountered an asterisk, then this is a generator method on an + // object literal and cannot be a binding pattern. + if (nextToken() === SyntaxKind.AsteriskToken) { + return Tristate.False; + } + + return Tristate.Unknown; + } + + // Simple case: "(..." // This is an arrow function with a rest parameter. - if (second === SyntaxKind.DotDotDotToken && !possiblyInObjectBindingPattern) { - // if we are possibly in an array binding pattern, then this may be a lambda, otherwise it must be a lambda. - return possiblyInArrayBindingPattern ? Tristate.Unknown : Tristate.True; + if (second === SyntaxKind.DotDotDotToken) { + return Tristate.True; } - // If we had "(" followed by something that's not an identifier, + // If we had something like "(" followed by something that's not an identifier, // then this definitely doesn't look like a lambda. // Note: we could be a little more lenient and allow // "(public" or "(private". These would not ever actually be allowed, @@ -3253,9 +3267,9 @@ module ts { return Tristate.False; } - // If we have something like "(a:", but not "({ a:", then we must have a + // If we have something like "(a:", then we may have a // type-annotated parameter in an arrow function expression. - if (nextToken() === SyntaxKind.ColonToken && !possiblyInObjectBindingPattern) { + if (nextToken() === SyntaxKind.ColonToken) { return Tristate.True; } diff --git a/tests/baselines/reference/emitArrowFunctionES6.js b/tests/baselines/reference/emitArrowFunctionES6.js index 603b2737fc5..f9f5669c92e 100644 --- a/tests/baselines/reference/emitArrowFunctionES6.js +++ b/tests/baselines/reference/emitArrowFunctionES6.js @@ -6,6 +6,18 @@ var f4 = (x: string, y: number, z=10) => { } function foo(func: () => boolean) { } foo(() => true); foo(() => { return false; }); + +// Binding patterns in arrow functions +var p1 = ([a]) => { }; +var p2 = ([...a]) => { }; +var p3 = ([, a]) => { }; +var p4 = ([, ...a]) => { }; +var p5 = ([a = 1]) => { }; +var p6 = ({ a }) => { }; +var p7 = ({ a: { b } }) => { }; +var p8 = ({ a = 1 }) => { }; +var p9 = ({ a: { b = 1 } = { b: 1 } }) => { }; +var p10 = ([{ value, done }]) => { }; //// [emitArrowFunctionES6.js] @@ -16,3 +28,14 @@ var f4 = (x, y, z = 10) => { }; function foo(func) { } foo(() => true); foo(() => { return false; }); +// Binding patterns in arrow functions +var p1 = ([a]) => { }; +var p2 = ([...a]) => { }; +var p3 = ([, a]) => { }; +var p4 = ([, ...a]) => { }; +var p5 = ([a = 1]) => { }; +var p6 = ({ a }) => { }; +var p7 = ({ a: { b } }) => { }; +var p8 = ({ a = 1 }) => { }; +var p9 = ({ a: { b = 1 } = { b: 1 } }) => { }; +var p10 = ([{ value, done }]) => { }; diff --git a/tests/baselines/reference/emitArrowFunctionES6.types b/tests/baselines/reference/emitArrowFunctionES6.types index 1f0c1941bdb..7ded82f9a98 100644 --- a/tests/baselines/reference/emitArrowFunctionES6.types +++ b/tests/baselines/reference/emitArrowFunctionES6.types @@ -37,3 +37,59 @@ foo(() => { return false; }); >foo : (func: () => boolean) => void >() => { return false; } : () => boolean +// Binding patterns in arrow functions +var p1 = ([a]) => { }; +>p1 : ([a]: [any]) => void +>([a]) => { } : ([a]: [any]) => void +>a : any + +var p2 = ([...a]) => { }; +>p2 : ([...a]: any[]) => void +>([...a]) => { } : ([...a]: any[]) => void +>a : any[] + +var p3 = ([, a]) => { }; +>p3 : ([, a]: [any, any]) => void +>([, a]) => { } : ([, a]: [any, any]) => void +>a : any + +var p4 = ([, ...a]) => { }; +>p4 : ([, ...a]: any[]) => void +>([, ...a]) => { } : ([, ...a]: any[]) => void +>a : any[] + +var p5 = ([a = 1]) => { }; +>p5 : ([a = 1]: [number]) => void +>([a = 1]) => { } : ([a = 1]: [number]) => void +>a : number + +var p6 = ({ a }) => { }; +>p6 : ({ a }: { a: any; }) => void +>({ a }) => { } : ({ a }: { a: any; }) => void +>a : any + +var p7 = ({ a: { b } }) => { }; +>p7 : ({ a: { b } }: { a: { b: any; }; }) => void +>({ a: { b } }) => { } : ({ a: { b } }: { a: { b: any; }; }) => void +>a : unknown +>b : any + +var p8 = ({ a = 1 }) => { }; +>p8 : ({ a = 1 }: { a?: number; }) => void +>({ a = 1 }) => { } : ({ a = 1 }: { a?: number; }) => void +>a : number + +var p9 = ({ a: { b = 1 } = { b: 1 } }) => { }; +>p9 : ({ a: { b = 1 } = { b: 1 } }: { a?: { b: number; }; }) => void +>({ a: { b = 1 } = { b: 1 } }) => { } : ({ a: { b = 1 } = { b: 1 } }: { a?: { b: number; }; }) => void +>a : unknown +>b : number +>{ b: 1 } : { b: number; } +>b : number + +var p10 = ([{ value, done }]) => { }; +>p10 : ([{ value, done }]: [{ value: any; done: any; }]) => void +>([{ value, done }]) => { } : ([{ value, done }]: [{ value: any; done: any; }]) => void +>value : any +>done : any + diff --git a/tests/cases/conformance/es6/arrowFunction/emitArrowFunctionES6.ts b/tests/cases/conformance/es6/arrowFunction/emitArrowFunctionES6.ts index d56d07c6c4e..9dff987cd64 100644 --- a/tests/cases/conformance/es6/arrowFunction/emitArrowFunctionES6.ts +++ b/tests/cases/conformance/es6/arrowFunction/emitArrowFunctionES6.ts @@ -6,3 +6,15 @@ var f4 = (x: string, y: number, z=10) => { } function foo(func: () => boolean) { } foo(() => true); foo(() => { return false; }); + +// Binding patterns in arrow functions +var p1 = ([a]) => { }; +var p2 = ([...a]) => { }; +var p3 = ([, a]) => { }; +var p4 = ([, ...a]) => { }; +var p5 = ([a = 1]) => { }; +var p6 = ({ a }) => { }; +var p7 = ({ a: { b } }) => { }; +var p8 = ({ a = 1 }) => { }; +var p9 = ({ a: { b = 1 } = { b: 1 } }) => { }; +var p10 = ([{ value, done }]) => { };