From c89f2b75ad7e7557a6df33918b62ede8b149fce4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 2 Feb 2016 14:14:37 -0800 Subject: [PATCH 1/4] Properly parse function/constructor types with destructuring parameters --- src/compiler/parser.ts | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4ec83277e3e6f..77f50a9bd87b5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2450,10 +2450,27 @@ namespace ts { if (token === SyntaxKind.LessThanToken) { return true; } - return token === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType); } + function skipParameterStart(): boolean { + if (isModifierKind(token)) { + // Skip modifiers + parseModifiers(); + } + if (isIdentifier()) { + nextToken(); + return true; + } + if (token === SyntaxKind.OpenBracketToken || token === SyntaxKind.OpenBraceToken) { + // Return true if we can parse an array or object binding pattern with no errors + const count = parseDiagnostics.length; + parseIdentifierOrPattern(); + return count === parseDiagnostics.length; + } + return false; + } + function isUnambiguouslyStartOfFunctionType() { nextToken(); if (token === SyntaxKind.CloseParenToken || token === SyntaxKind.DotDotDotToken) { @@ -2461,16 +2478,15 @@ namespace ts { // ( ... return true; } - if (isIdentifier() || isModifierKind(token)) { - nextToken(); + if (skipParameterStart()) { + // We successfully skipped modifiers (if any) and an identifier or binding pattern, + // now see if we have something that indicates a parameter declaration if (token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || - token === SyntaxKind.QuestionToken || token === SyntaxKind.EqualsToken || - isIdentifier() || isModifierKind(token)) { - // ( id : - // ( id , - // ( id ? - // ( id = - // ( modifier id + token === SyntaxKind.QuestionToken || token === SyntaxKind.EqualsToken) { + // ( xxx : + // ( xxx , + // ( xxx ? + // ( xxx = return true; } if (token === SyntaxKind.CloseParenToken) { From 5643f911c7a63be09cb574840d444fea1e3f9a4f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 2 Feb 2016 14:14:55 -0800 Subject: [PATCH 2/4] Adding test --- .../destructuringInFunctionType.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/cases/conformance/es6/destructuring/destructuringInFunctionType.ts diff --git a/tests/cases/conformance/es6/destructuring/destructuringInFunctionType.ts b/tests/cases/conformance/es6/destructuring/destructuringInFunctionType.ts new file mode 100644 index 0000000000000..51333b1ca5333 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringInFunctionType.ts @@ -0,0 +1,22 @@ +// @declaration: true + +interface a { a } +interface b { b } +interface c { c } + +type T1 = ([a, b, c]); +type F1 = ([a, b, c]) => void; + +type T2 = ({ a }); +type F2 = ({ a }) => void; + +type T3 = ([{ a: b }, { b: a }]); +type F3 = ([{ a: b }, { b: a }]) => void; + +type T4 = ([{ a: [b, c] }]); +type F4 = ([{ a: [b, c] }]) => void; + +type C1 = new ([{ a: [b, c] }]) => void; + +var v1 = ([a, b, c]) => "hello"; +var v2: ([a, b, c]) => string; From 979186fad9a6e28a4f1fb8446621a0e88343e9fa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 2 Feb 2016 14:15:26 -0800 Subject: [PATCH 3/4] Accepting new baselines --- .../reference/destructuringInFunctionType.js | 61 ++++++++++++++ .../destructuringInFunctionType.symbols | 78 ++++++++++++++++++ .../destructuringInFunctionType.types | 80 +++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 tests/baselines/reference/destructuringInFunctionType.js create mode 100644 tests/baselines/reference/destructuringInFunctionType.symbols create mode 100644 tests/baselines/reference/destructuringInFunctionType.types diff --git a/tests/baselines/reference/destructuringInFunctionType.js b/tests/baselines/reference/destructuringInFunctionType.js new file mode 100644 index 0000000000000..ac187f5b43db9 --- /dev/null +++ b/tests/baselines/reference/destructuringInFunctionType.js @@ -0,0 +1,61 @@ +//// [destructuringInFunctionType.ts] + +interface a { a } +interface b { b } +interface c { c } + +type T1 = ([a, b, c]); +type F1 = ([a, b, c]) => void; + +type T2 = ({ a }); +type F2 = ({ a }) => void; + +type T3 = ([{ a: b }, { b: a }]); +type F3 = ([{ a: b }, { b: a }]) => void; + +type T4 = ([{ a: [b, c] }]); +type F4 = ([{ a: [b, c] }]) => void; + +type C1 = new ([{ a: [b, c] }]) => void; + +var v1 = ([a, b, c]) => "hello"; +var v2: ([a, b, c]) => string; + + +//// [destructuringInFunctionType.js] +var v1 = function (_a) { + var a = _a[0], b = _a[1], c = _a[2]; + return "hello"; +}; +var v2; + + +//// [destructuringInFunctionType.d.ts] +interface a { + a: any; +} +interface b { + b: any; +} +interface c { + c: any; +} +declare type T1 = ([a, b, c]); +declare type F1 = ([a, b, c]) => void; +declare type T2 = ({ + a; +}); +declare type F2 = ({a}) => void; +declare type T3 = ([{ + a: b; +}, { + b: a; +}]); +declare type F3 = ([{a: b}, {b: a}]) => void; +declare type T4 = ([{ + a: [b, c]; +}]); +declare type F4 = ([{a: [b, c]}]) => void; +declare type C1 = new ([{a: [b, c]}]) => void; +declare var v1: ([a, b, c]: [any, any, any]) => string; +declare var v2: ([a, b, c]) => string; diff --git a/tests/baselines/reference/destructuringInFunctionType.symbols b/tests/baselines/reference/destructuringInFunctionType.symbols new file mode 100644 index 0000000000000..8b573905b76ae --- /dev/null +++ b/tests/baselines/reference/destructuringInFunctionType.symbols @@ -0,0 +1,78 @@ +=== tests/cases/conformance/es6/destructuring/destructuringInFunctionType.ts === + +interface a { a } +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 0, 0)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 1, 13)) + +interface b { b } +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 1, 17)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 2, 13)) + +interface c { c } +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 2, 17)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 3, 13)) + +type T1 = ([a, b, c]); +>T1 : Symbol(T1, Decl(destructuringInFunctionType.ts, 3, 17)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 0, 0)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 1, 17)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 2, 17)) + +type F1 = ([a, b, c]) => void; +>F1 : Symbol(F1, Decl(destructuringInFunctionType.ts, 5, 22)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 6, 12)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 6, 14)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 6, 17)) + +type T2 = ({ a }); +>T2 : Symbol(T2, Decl(destructuringInFunctionType.ts, 6, 30)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 8, 12)) + +type F2 = ({ a }) => void; +>F2 : Symbol(F2, Decl(destructuringInFunctionType.ts, 8, 18)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 9, 12)) + +type T3 = ([{ a: b }, { b: a }]); +>T3 : Symbol(T3, Decl(destructuringInFunctionType.ts, 9, 26)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 11, 13)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 1, 17)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 11, 23)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 0, 0)) + +type F3 = ([{ a: b }, { b: a }]) => void; +>F3 : Symbol(F3, Decl(destructuringInFunctionType.ts, 11, 33)) +>a : Symbol(a) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 12, 13)) +>b : Symbol(b) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 12, 23)) + +type T4 = ([{ a: [b, c] }]); +>T4 : Symbol(T4, Decl(destructuringInFunctionType.ts, 12, 41)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 14, 13)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 1, 17)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 2, 17)) + +type F4 = ([{ a: [b, c] }]) => void; +>F4 : Symbol(F4, Decl(destructuringInFunctionType.ts, 14, 28)) +>a : Symbol(a) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 15, 18)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 15, 20)) + +type C1 = new ([{ a: [b, c] }]) => void; +>C1 : Symbol(C1, Decl(destructuringInFunctionType.ts, 15, 36)) +>a : Symbol(a) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 17, 22)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 17, 24)) + +var v1 = ([a, b, c]) => "hello"; +>v1 : Symbol(v1, Decl(destructuringInFunctionType.ts, 19, 3)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 19, 11)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 19, 13)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 19, 16)) + +var v2: ([a, b, c]) => string; +>v2 : Symbol(v2, Decl(destructuringInFunctionType.ts, 20, 3)) +>a : Symbol(a, Decl(destructuringInFunctionType.ts, 20, 10)) +>b : Symbol(b, Decl(destructuringInFunctionType.ts, 20, 12)) +>c : Symbol(c, Decl(destructuringInFunctionType.ts, 20, 15)) + diff --git a/tests/baselines/reference/destructuringInFunctionType.types b/tests/baselines/reference/destructuringInFunctionType.types new file mode 100644 index 0000000000000..8786bbd0bb966 --- /dev/null +++ b/tests/baselines/reference/destructuringInFunctionType.types @@ -0,0 +1,80 @@ +=== tests/cases/conformance/es6/destructuring/destructuringInFunctionType.ts === + +interface a { a } +>a : a +>a : any + +interface b { b } +>b : b +>b : any + +interface c { c } +>c : c +>c : any + +type T1 = ([a, b, c]); +>T1 : [a, b, c] +>a : a +>b : b +>c : c + +type F1 = ([a, b, c]) => void; +>F1 : ([a, b, c]: [any, any, any]) => void +>a : any +>b : any +>c : any + +type T2 = ({ a }); +>T2 : { a: any; } +>a : any + +type F2 = ({ a }) => void; +>F2 : ({ a }: { a: any; }) => void +>a : any + +type T3 = ([{ a: b }, { b: a }]); +>T3 : [{ a: b; }, { b: a; }] +>a : b +>b : b +>b : a +>a : a + +type F3 = ([{ a: b }, { b: a }]) => void; +>F3 : ([{ a: b }, { b: a }]: [{ a: any; }, { b: any; }]) => void +>a : any +>b : any +>b : any +>a : any + +type T4 = ([{ a: [b, c] }]); +>T4 : [{ a: [b, c]; }] +>a : [b, c] +>b : b +>c : c + +type F4 = ([{ a: [b, c] }]) => void; +>F4 : ([{ a: [b, c] }]: [{ a: [any, any]; }]) => void +>a : any +>b : any +>c : any + +type C1 = new ([{ a: [b, c] }]) => void; +>C1 : new ([{ a: [b, c] }]: [{ a: [any, any]; }]) => void +>a : any +>b : any +>c : any + +var v1 = ([a, b, c]) => "hello"; +>v1 : ([a, b, c]: [any, any, any]) => string +>([a, b, c]) => "hello" : ([a, b, c]: [any, any, any]) => string +>a : any +>b : any +>c : any +>"hello" : string + +var v2: ([a, b, c]) => string; +>v2 : ([a, b, c]: [any, any, any]) => string +>a : any +>b : any +>c : any + From 98e8a25d1e5525cd7a9ae6d5b12f620ab658f34a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Feb 2016 06:52:53 -0800 Subject: [PATCH 4/4] Addressing CR feedback --- src/compiler/parser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 77f50a9bd87b5..fa17864166d6f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2464,9 +2464,9 @@ namespace ts { } if (token === SyntaxKind.OpenBracketToken || token === SyntaxKind.OpenBraceToken) { // Return true if we can parse an array or object binding pattern with no errors - const count = parseDiagnostics.length; + const previousErrorCount = parseDiagnostics.length; parseIdentifierOrPattern(); - return count === parseDiagnostics.length; + return previousErrorCount === parseDiagnostics.length; } return false; } @@ -2492,7 +2492,7 @@ namespace ts { if (token === SyntaxKind.CloseParenToken) { nextToken(); if (token === SyntaxKind.EqualsGreaterThanToken) { - // ( id ) => + // ( xxx ) => return true; } }