From 5b6bb5b649a823315facce210041f7a3a5309133 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 22 Jul 2014 16:47:09 -0700 Subject: [PATCH 1/4] Improved lookahead for arrow functions. Fixes issue #34. Specifically: * We no longer automatically assume "()" is a function expression. It must be followed by an arrow, colon, or curly brace. * If an arrow is missing following a signature, but a curly brace is present, we assume the user forgot the arrow and try to parse the body anyway. --- src/compiler/parser.ts | 49 ++++-- .../arrowFunctionsMissingTokens.errors.txt | 145 ++++++++++++++++++ .../reference/emptyMemberAccess.errors.txt | 8 +- .../reference/es6ClassTest9.errors.txt | 4 +- .../reference/parser566700.errors.txt | 4 +- ...erEmptyParenthesizedExpression1.errors.txt | 8 +- ...parserErrorRecovery_Expression1.errors.txt | 4 +- .../uncaughtCompilerError2.errors.txt | 8 +- .../compiler/arrowFunctionsMissingTokens.ts | 66 ++++++++ 9 files changed, 259 insertions(+), 37 deletions(-) create mode 100644 tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt create mode 100644 tests/cases/compiler/arrowFunctionsMissingTokens.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0304586bbca2f..85eb373c4494c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1445,6 +1445,7 @@ module ts { function tryParseParenthesizedArrowFunctionExpression(): Expression { var pos = getNodePos(); + // Whether we are certain that we should parse an arrow expression. var triState = isParenthesizedArrowFunctionExpression(); // It is not a parenthesized arrow function. @@ -1457,11 +1458,12 @@ module ts { var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); // If we have an arrow, then try to parse the body. - if (parseExpected(SyntaxKind.EqualsGreaterThanToken)) { - return parseArrowExpressionTail(pos, sig, /*noIn:*/ false); + // Even if not, try to parse if we have an opening brace, just in case we're in an error state. + if (parseExpected(SyntaxKind.EqualsGreaterThanToken) || token === SyntaxKind.OpenBraceToken) { + return parseArrowExpressionTail(pos, sig, /* noIn: */ false); } - // If not, we're probably better off bailing out and returning a bogus function expression. else { + // If not, we're probably better off bailing out and returning a bogus function expression. return makeFunctionExpression(SyntaxKind.ArrowFunction, pos, /* name */ undefined, sig, createMissingNode()); } } @@ -1477,29 +1479,44 @@ module ts { } } - // True -> There is definitely a parenthesized arrow function here. - // False -> There is definitely *not* a parenthesized arrow function here. + // True -> We definitely expect a parenthesized arrow function here. + // False -> There *cannot* be a parenthesized arrow function here. // Unknown -> There *might* be a parenthesized arrow function here. - // Speculatively look ahead to be sure. + // Speculatively look ahead to be sure, and rollback if not. function isParenthesizedArrowFunctionExpression(): Tristate { if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { return lookAhead(() => { var first = token; - nextToken(); + var second = nextToken(); + if (first === SyntaxKind.OpenParenToken) { - if (token === SyntaxKind.CloseParenToken || token === SyntaxKind.DotDotDotToken) { - // Simple cases. if we see () or (... then presume that presume - // that this must be an arrow function. Note, this may be too aggressive - // for the "()" case. It's not uncommon for this to appear while editing - // code. We should look to see if there's actually a => before proceeding. + if (second === SyntaxKind.CloseParenToken) { + // Simple cases: "() =>", "(): ", and "() {". + // This is an arrow function with no parameters. + // The last one is not actually an arrow function, + // but this is probably what the user intended. + var third = nextToken(); + switch (third) { + case SyntaxKind.EqualsGreaterThanToken: + case SyntaxKind.ColonToken: + case SyntaxKind.OpenBraceToken: + return Tristate.True; + default: + return Tristate.False; + } + } + + // Simple case: "(..." + // This is an arrow function with a rest parameter. + if (second === SyntaxKind.DotDotDotToken) { return Tristate.True; } + // We had "(" not followed by an identifier. 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, + // but we could provide a good error message instead of bailing out. if (!isIdentifier()) { - // We had "(" not followed by an identifier. 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, - // but we could provide a good error message instead of bailing out. return Tristate.False; } diff --git a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt new file mode 100644 index 0000000000000..b9d139dba25e9 --- /dev/null +++ b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt @@ -0,0 +1,145 @@ +==== tests/cases/compiler/arrowFunctionsMissingTokens.ts (39 errors) ==== + + module missingArrowsWithCurly { + var a = () { }; + ~ +!!! '=>' expected. + + var b = (): void { } + ~ +!!! '=>' expected. + + var c = (x) { }; + ~ +!!! ',' expected. + ~ +!!! Cannot find name 'x'. + + var d = (x: number, y: string) { }; + ~ +!!! ')' expected. + ~ +!!! ',' expected. + ~ +!!! Variable declaration expected. + ~ +!!! Cannot find name 'x'. + + var e = (x: number, y: string): void { }; + ~ +!!! ')' expected. + ~ +!!! ',' expected. + ~ +!!! Variable declaration expected. + ~~~~ +!!! Variable declaration expected. + ~ +!!! Cannot find name 'x'. + } + + module missingCurliesWithArrow { + module withStatement { + var a = () => var k = 10;}; + ~~~ +!!! '{' expected. + + var b = (): void => var k = 10;} + ~~~ +!!! '{' expected. + + var c = (x) => var k = 10;}; + ~~~ +!!! '{' expected. + + var d = (x: number, y: string) => var k = 10;}; + ~~~ +!!! '{' expected. + + var e = (x: number, y: string): void => var k = 10;}; + ~~~ +!!! '{' expected. + + var f = () => var k = 10;} + ~~~ +!!! '{' expected. + } + + module withoutStatement { + var a = () => }; + ~ +!!! Expression expected. + + var b = (): void => } + ~ +!!! Expression expected. + + var c = (x) => }; + ~ +!!! Expression expected. + + var d = (x: number, y: string) => }; + ~ +!!! Expression expected. + + var e = (x: number, y: string): void => }; + ~ +!!! Expression expected. + + var f = () => } + ~ +!!! Expression expected. + } + ~ +!!! Declaration or statement expected. + } + ~ +!!! Declaration or statement expected. + + module ceci_nEst_pas_une_arrow_function { + var a = (); + ~ +!!! Expression expected. + + var b = (): void; + ~ +!!! '=>' expected. + + var c = (x); + ~ +!!! Cannot find name 'x'. + + var d = (x: number, y: string); + ~ +!!! ')' expected. + ~ +!!! ',' expected. + ~ +!!! Cannot find name 'x'. + + var e = (x: number, y: string): void; + ~ +!!! ')' expected. + ~ +!!! ',' expected. + ~ +!!! Variable declaration expected. + ~~~~ +!!! Variable declaration expected. + ~ +!!! Expression expected. + ~ +!!! Cannot find name 'x'. + } + + module okay { + var a = () => { }; + + var b = (): void => { } + + var c = (x) => { }; + + var d = (x: number, y: string) => { }; + + var e = (x: number, y: string): void => { }; + } \ No newline at end of file diff --git a/tests/baselines/reference/emptyMemberAccess.errors.txt b/tests/baselines/reference/emptyMemberAccess.errors.txt index 122c3957554c6..19c24099d948b 100644 --- a/tests/baselines/reference/emptyMemberAccess.errors.txt +++ b/tests/baselines/reference/emptyMemberAccess.errors.txt @@ -1,11 +1,9 @@ -==== tests/cases/compiler/emptyMemberAccess.ts (2 errors) ==== +==== tests/cases/compiler/emptyMemberAccess.ts (1 errors) ==== function getObj() { ().toString(); - ~ -!!! '=>' expected. - ~~~~~~~~ -!!! Cannot find name 'toString'. + ~ +!!! Expression expected. } \ No newline at end of file diff --git a/tests/baselines/reference/es6ClassTest9.errors.txt b/tests/baselines/reference/es6ClassTest9.errors.txt index f5856c71918cc..1b8be82fc9dde 100644 --- a/tests/baselines/reference/es6ClassTest9.errors.txt +++ b/tests/baselines/reference/es6ClassTest9.errors.txt @@ -2,8 +2,8 @@ declare class foo(); ~ !!! '{' expected. - ~ -!!! '=>' expected. + ~ +!!! Expression expected. function foo() {} ~~~ !!! Duplicate identifier 'foo'. diff --git a/tests/baselines/reference/parser566700.errors.txt b/tests/baselines/reference/parser566700.errors.txt index 63093a1b5dfda..ed2ca730caadf 100644 --- a/tests/baselines/reference/parser566700.errors.txt +++ b/tests/baselines/reference/parser566700.errors.txt @@ -1,4 +1,4 @@ ==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser566700.ts (1 errors) ==== var v = ()({}); - ~ -!!! '=>' expected. \ No newline at end of file + ~ +!!! Expression expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserEmptyParenthesizedExpression1.errors.txt b/tests/baselines/reference/parserEmptyParenthesizedExpression1.errors.txt index d84b0a9755a3b..c65700bc5e204 100644 --- a/tests/baselines/reference/parserEmptyParenthesizedExpression1.errors.txt +++ b/tests/baselines/reference/parserEmptyParenthesizedExpression1.errors.txt @@ -1,8 +1,6 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEmptyParenthesizedExpression1.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEmptyParenthesizedExpression1.ts (1 errors) ==== function getObj() { ().toString(); - ~ -!!! '=>' expected. - ~~~~~~~~ -!!! Cannot find name 'toString'. + ~ +!!! Expression expected. } \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_Expression1.errors.txt b/tests/baselines/reference/parserErrorRecovery_Expression1.errors.txt index e8f6af701af6e..6e6a450ec0295 100644 --- a/tests/baselines/reference/parserErrorRecovery_Expression1.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_Expression1.errors.txt @@ -1,4 +1,4 @@ ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Expressions/parserErrorRecovery_Expression1.ts (1 errors) ==== var v = ()({}); - ~ -!!! '=>' expected. \ No newline at end of file + ~ +!!! Expression expected. \ No newline at end of file diff --git a/tests/baselines/reference/uncaughtCompilerError2.errors.txt b/tests/baselines/reference/uncaughtCompilerError2.errors.txt index 70395e04bdd20..455e047034f87 100644 --- a/tests/baselines/reference/uncaughtCompilerError2.errors.txt +++ b/tests/baselines/reference/uncaughtCompilerError2.errors.txt @@ -1,9 +1,7 @@ -==== tests/cases/compiler/uncaughtCompilerError2.ts (2 errors) ==== +==== tests/cases/compiler/uncaughtCompilerError2.ts (1 errors) ==== function getObj() { ().toString(); - ~ -!!! '=>' expected. - ~~~~~~~~ -!!! Cannot find name 'toString'. + ~ +!!! Expression expected. } \ No newline at end of file diff --git a/tests/cases/compiler/arrowFunctionsMissingTokens.ts b/tests/cases/compiler/arrowFunctionsMissingTokens.ts new file mode 100644 index 0000000000000..0e1e693180774 --- /dev/null +++ b/tests/cases/compiler/arrowFunctionsMissingTokens.ts @@ -0,0 +1,66 @@ + +module missingArrowsWithCurly { + var a = () { }; + + var b = (): void { } + + var c = (x) { }; + + var d = (x: number, y: string) { }; + + var e = (x: number, y: string): void { }; +} + +module missingCurliesWithArrow { + module withStatement { + var a = () => var k = 10;}; + + var b = (): void => var k = 10;} + + var c = (x) => var k = 10;}; + + var d = (x: number, y: string) => var k = 10;}; + + var e = (x: number, y: string): void => var k = 10;}; + + var f = () => var k = 10;} + } + + module withoutStatement { + var a = () => }; + + var b = (): void => } + + var c = (x) => }; + + var d = (x: number, y: string) => }; + + var e = (x: number, y: string): void => }; + + var f = () => } + } +} + +module ceci_nEst_pas_une_arrow_function { + var a = (); + + var b = (): void; + + var c = (x); + + var d = (x: number, y: string); + + var e = (x: number, y: string): void; +} + +module okay { + var a = () => { }; + + var b = (): void => { } + + var c = (x) => { }; + + var d = (x: number, y: string) => { }; + + var e = (x: number, y: string): void => { }; +} \ No newline at end of file From 5fc2792297ad85234df29accc0641da736e1e124 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 23 Jul 2014 11:49:51 -0700 Subject: [PATCH 2/4] Covered more cases for arrow functions omitting arrows. Specifically where we have a full signature followed by an open curly brace. --- src/compiler/parser.ts | 18 ++++++++----- .../arrowFunctionsMissingTokens.errors.txt | 26 ++++--------------- .../fatarrowfunctionsErrors.errors.txt | 22 +++------------- .../invalidTryStatements2.errors.txt | 6 ++--- 4 files changed, 22 insertions(+), 50 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 85eb373c4494c..cdcf9345be98b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1445,7 +1445,7 @@ module ts { function tryParseParenthesizedArrowFunctionExpression(): Expression { var pos = getNodePos(); - // Whether we are certain that we should parse an arrow expression. + // Indicates whether we are certain that we should parse an arrow expression. var triState = isParenthesizedArrowFunctionExpression(); // It is not a parenthesized arrow function. @@ -1470,11 +1470,12 @@ module ts { // Otherwise, *maybe* we had an arrow function and we need to *try* to parse it out // (which will ensure we rollback if we fail). - var sig = tryParse(parseSignatureAndArrow); + var sig = tryParse(parseSignatureIfArrowOrBraceFollows); if (sig === undefined) { return undefined; } else { + parseExpected(SyntaxKind.EqualsGreaterThanToken); return parseArrowExpressionTail(pos, sig, /*noIn:*/ false); } } @@ -1512,8 +1513,9 @@ module ts { return Tristate.True; } - // We had "(" not followed by an identifier. This definitely doesn't - // look like a lambda. Note: we could be a little more lenient and allow + // If we had "(" 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, // but we could provide a good error message instead of bailing out. if (!isIdentifier()) { @@ -1543,10 +1545,12 @@ module ts { return Tristate.False; } - function parseSignatureAndArrow(): ParsedSignature { + function parseSignatureIfArrowOrBraceFollows(): ParsedSignature { var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); - parseExpected(SyntaxKind.EqualsGreaterThanToken); - return sig; + if (token === SyntaxKind.EqualsGreaterThanToken || token === SyntaxKind.OpenBraceToken) { + return sig; + } + return undefined; } function parseArrowExpressionTail(pos: number, sig: ParsedSignature, noIn: boolean): FunctionExpression { diff --git a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt index b9d139dba25e9..61a3bb002e711 100644 --- a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt +++ b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/arrowFunctionsMissingTokens.ts (39 errors) ==== +==== tests/cases/compiler/arrowFunctionsMissingTokens.ts (31 errors) ==== module missingArrowsWithCurly { var a = () { }; @@ -11,31 +11,15 @@ var c = (x) { }; ~ -!!! ',' expected. - ~ -!!! Cannot find name 'x'. +!!! '=>' expected. var d = (x: number, y: string) { }; - ~ -!!! ')' expected. - ~ -!!! ',' expected. ~ -!!! Variable declaration expected. - ~ -!!! Cannot find name 'x'. +!!! '=>' expected. var e = (x: number, y: string): void { }; - ~ -!!! ')' expected. - ~ -!!! ',' expected. - ~ -!!! Variable declaration expected. - ~~~~ -!!! Variable declaration expected. - ~ -!!! Cannot find name 'x'. + ~ +!!! '=>' expected. } module missingCurliesWithArrow { diff --git a/tests/baselines/reference/fatarrowfunctionsErrors.errors.txt b/tests/baselines/reference/fatarrowfunctionsErrors.errors.txt index d04b93b10ad42..132e369a64330 100644 --- a/tests/baselines/reference/fatarrowfunctionsErrors.errors.txt +++ b/tests/baselines/reference/fatarrowfunctionsErrors.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/fatarrowfunctionsErrors.ts (25 errors) ==== +==== tests/cases/compiler/fatarrowfunctionsErrors.ts (18 errors) ==== foo((...Far:any[])=>{return 0;}) ~~~ !!! Cannot find name 'foo'. @@ -39,25 +39,11 @@ ~ !!! '=>' expected. var x2 = (a:number) :void {}; - ~ -!!! ')' expected. - ~ -!!! ',' expected. - ~ -!!! Variable declaration expected. - ~~~~ -!!! Variable declaration expected. - ~ -!!! Cannot find name 'a'. + ~ +!!! '=>' expected. var x3 = (a:number) {}; - ~ -!!! ')' expected. - ~ -!!! ',' expected. ~ -!!! Variable declaration expected. - ~ -!!! Cannot find name 'a'. +!!! '=>' expected. var x4= (...a: any[]) { }; ~ !!! '=>' expected. \ No newline at end of file diff --git a/tests/baselines/reference/invalidTryStatements2.errors.txt b/tests/baselines/reference/invalidTryStatements2.errors.txt index 3a9aa15b54038..fcb8ad3560d98 100644 --- a/tests/baselines/reference/invalidTryStatements2.errors.txt +++ b/tests/baselines/reference/invalidTryStatements2.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts (5 errors) ==== +==== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts (4 errors) ==== function fn() { try { } catch { // syntax error, missing '(x)' @@ -10,9 +10,7 @@ ~~~~~ !!! Statement expected. ~ -!!! ';' expected. - ~ -!!! Cannot find name 'x'. +!!! '=>' expected. finally{ } // error missing try ~~~~~~~ From 57d7cf54c696a67017791db09976df4769e1d834 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 23 Jul 2014 13:31:24 -0700 Subject: [PATCH 3/4] Improved "certainty" when parsing arrow-function-lookin' expressions. --- src/compiler/parser.ts | 22 +++++++++++++++---- .../arrowFunctionsMissingTokens.errors.txt | 22 ++++--------------- ...serErrorRecovery_ParameterList5.errors.txt | 12 ++++------ .../parserUnterminatedGeneric2.errors.txt | 22 +++---------------- .../parserX_ArrowFunction1.errors.txt | 10 ++------- 5 files changed, 31 insertions(+), 57 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index cdcf9345be98b..df45db2a41511 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1448,12 +1448,10 @@ module ts { // Indicates whether we are certain that we should parse an arrow expression. var triState = isParenthesizedArrowFunctionExpression(); - // It is not a parenthesized arrow function. if (triState === Tristate.False) { return undefined; } - // If we're certain that we have an arrow function expression, then just parse one out. if (triState === Tristate.True) { var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); @@ -1468,8 +1466,8 @@ module ts { } } - // Otherwise, *maybe* we had an arrow function and we need to *try* to parse it out - // (which will ensure we rollback if we fail). + // *Maybe* we had an arrow function and we need to try to parse it out, + // rolling back and trying other parses if we fail. var sig = tryParse(parseSignatureIfArrowOrBraceFollows); if (sig === undefined) { return undefined; @@ -1522,6 +1520,12 @@ module ts { return Tristate.False; } + // If we have something like "(a:", then we must have a + // type-annotated parameter in an arrow function expression. + if (nextToken() === SyntaxKind.ColonToken) { + return Tristate.True; + } + // This *could* be a parenthesized arrow function. // Return Unknown to let the caller know. return Tristate.Unknown; @@ -1547,9 +1551,19 @@ module ts { function parseSignatureIfArrowOrBraceFollows(): ParsedSignature { var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); + + // Parsing a signature isn't enough. + // Parenthesized arrow signatures often look like other valid expressions. + // For instance: + // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. + // - "(x,y)" is a comma expression parsed as a signature with two parameters. + // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. + // + // So we need just a bit of lookahead to ensure that it can only be a signature. if (token === SyntaxKind.EqualsGreaterThanToken || token === SyntaxKind.OpenBraceToken) { return sig; } + return undefined; } diff --git a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt index 61a3bb002e711..f6072db083907 100644 --- a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt +++ b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/arrowFunctionsMissingTokens.ts (31 errors) ==== +==== tests/cases/compiler/arrowFunctionsMissingTokens.ts (24 errors) ==== module missingArrowsWithCurly { var a = () { }; @@ -94,26 +94,12 @@ !!! Cannot find name 'x'. var d = (x: number, y: string); - ~ -!!! ')' expected. - ~ -!!! ',' expected. - ~ -!!! Cannot find name 'x'. + ~ +!!! '=>' expected. var e = (x: number, y: string): void; - ~ -!!! ')' expected. - ~ -!!! ',' expected. - ~ -!!! Variable declaration expected. - ~~~~ -!!! Variable declaration expected. ~ -!!! Expression expected. - ~ -!!! Cannot find name 'x'. +!!! '=>' expected. } module okay { diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt b/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt index 7e22c1e111f0d..ba862a3afb6fa 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt @@ -1,10 +1,6 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList5.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList5.ts (2 errors) ==== (a:number => { } - ~ -!!! ')' expected. ~~ -!!! ';' expected. - ~ -!!! Cannot find name 'a'. - ~~~~~~ -!!! Cannot find name 'number'. \ No newline at end of file +!!! ',' expected. + ~ +!!! ')' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserUnterminatedGeneric2.errors.txt b/tests/baselines/reference/parserUnterminatedGeneric2.errors.txt index f0ab0ad10b193..8d9a411a7eb64 100644 --- a/tests/baselines/reference/parserUnterminatedGeneric2.errors.txt +++ b/tests/baselines/reference/parserUnterminatedGeneric2.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserUnterminatedGeneric2.ts (23 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserUnterminatedGeneric2.ts (15 errors) ==== declare module ng { interfaceICompiledExpression { ~ @@ -6,24 +6,8 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! Cannot find name 'interfaceICompiledExpression'. (context: any, locals?: any): any; - ~ -!!! ')' expected. - ~ -!!! Expression expected. - ~ -!!! ';' expected. - ~ -!!! Statement expected. - ~~~~~~~ -!!! Cannot find name 'context'. - ~~~ -!!! Cannot find name 'any'. - ~~~~~~ -!!! Cannot find name 'locals'. - ~~~ -!!! Cannot find name 'any'. - ~~~ -!!! Cannot find name 'any'. + ~ +!!! '=>' expected. assign(context: any, value: any): any; ~ !!! ',' expected. diff --git a/tests/baselines/reference/parserX_ArrowFunction1.errors.txt b/tests/baselines/reference/parserX_ArrowFunction1.errors.txt index 68e0e0b6eb67f..2443366b41562 100644 --- a/tests/baselines/reference/parserX_ArrowFunction1.errors.txt +++ b/tests/baselines/reference/parserX_ArrowFunction1.errors.txt @@ -1,12 +1,6 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/parserX_ArrowFunction1.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/parserX_ArrowFunction1.ts (1 errors) ==== var v = (a: ) => { - ~ -!!! ')' expected. ~ -!!! Variable declaration expected. - ~~ -!!! ';' expected. - ~ -!!! Cannot find name 'a'. +!!! Type expected. }; \ No newline at end of file From b76c13cfd5724510158857d88c5607ccf1cbf080 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 24 Jul 2014 18:05:05 -0700 Subject: [PATCH 4/4] Addressed code review feedback. --- src/compiler/parser.ts | 40 ++++++++++--------- .../arrowFunctionsMissingTokens.errors.txt | 2 +- .../compiler/arrowFunctionsMissingTokens.ts | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index df45db2a41511..ba1bb0ed70055 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1468,14 +1468,14 @@ module ts { // *Maybe* we had an arrow function and we need to try to parse it out, // rolling back and trying other parses if we fail. - var sig = tryParse(parseSignatureIfArrowOrBraceFollows); - if (sig === undefined) { - return undefined; - } - else { + var sig = tryParseSignatureIfArrowOrBraceFollows(); + if (sig) { parseExpected(SyntaxKind.EqualsGreaterThanToken); return parseArrowExpressionTail(pos, sig, /*noIn:*/ false); } + else { + return undefined; + } } // True -> We definitely expect a parenthesized arrow function here. @@ -1549,22 +1549,24 @@ module ts { return Tristate.False; } - function parseSignatureIfArrowOrBraceFollows(): ParsedSignature { - var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); + function tryParseSignatureIfArrowOrBraceFollows(): ParsedSignature { + return tryParse(() => { + var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); - // Parsing a signature isn't enough. - // Parenthesized arrow signatures often look like other valid expressions. - // For instance: - // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. - // - "(x,y)" is a comma expression parsed as a signature with two parameters. - // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. - // - // So we need just a bit of lookahead to ensure that it can only be a signature. - if (token === SyntaxKind.EqualsGreaterThanToken || token === SyntaxKind.OpenBraceToken) { - return sig; - } + // Parsing a signature isn't enough. + // Parenthesized arrow signatures often look like other valid expressions. + // For instance: + // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. + // - "(x,y)" is a comma expression parsed as a signature with two parameters. + // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. + // + // So we need just a bit of lookahead to ensure that it can only be a signature. + if (token === SyntaxKind.EqualsGreaterThanToken || token === SyntaxKind.OpenBraceToken) { + return sig; + } - return undefined; + return undefined; + }); } function parseArrowExpressionTail(pos: number, sig: ParsedSignature, noIn: boolean): FunctionExpression { diff --git a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt index f6072db083907..69b94cd7d4654 100644 --- a/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt +++ b/tests/baselines/reference/arrowFunctionsMissingTokens.errors.txt @@ -80,7 +80,7 @@ ~ !!! Declaration or statement expected. - module ceci_nEst_pas_une_arrow_function { + module ce_nEst_pas_une_arrow_function { var a = (); ~ !!! Expression expected. diff --git a/tests/cases/compiler/arrowFunctionsMissingTokens.ts b/tests/cases/compiler/arrowFunctionsMissingTokens.ts index 0e1e693180774..bd3e25d56b4a7 100644 --- a/tests/cases/compiler/arrowFunctionsMissingTokens.ts +++ b/tests/cases/compiler/arrowFunctionsMissingTokens.ts @@ -41,7 +41,7 @@ module missingCurliesWithArrow { } } -module ceci_nEst_pas_une_arrow_function { +module ce_nEst_pas_une_arrow_function { var a = (); var b = (): void;