diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e57a3fa98f390..f055c326b0a33 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4695,24 +4695,7 @@ namespace ts { } } - // Given: - // x ? y => ({ y }) : z => ({ z }) - // We try to parse the body of the first arrow function by looking at: - // ({ y }) : z => ({ z }) - // This is a valid arrow function with "z" as the return type. - // - // But, if we're in the true side of a conditional expression, this colon - // terminates the expression, so we cannot allow a return type if we aren't - // certain whether or not the preceding text was parsed as a parameter list. - // - // For example, - // a() ? (b: number, c?: string): void => d() : e - // is determined by isParenthesizedArrowFunctionExpression to unambiguously - // be an arrow expression, so we allow a return type. - if (disallowReturnTypeInArrowFunction && token() === SyntaxKind.ColonToken) { - return undefined; - } - + const hasReturnColon = token() === SyntaxKind.ColonToken; const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) { return undefined; @@ -4748,6 +4731,31 @@ namespace ts { ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), disallowReturnTypeInArrowFunction) : parseIdentifier(); + // Given: + // x ? y => ({ y }) : z => ({ z }) + // We try to parse the body of the first arrow function by looking at: + // ({ y }) : z => ({ z }) + // This is a valid arrow function with "z" as the return type. + // + // But, if we're in the true side of a conditional expression, this colon + // terminates the expression, so we cannot allow a return type if we aren't + // certain whether or not the preceding text was parsed as a parameter list. + // + // For example, + // a() ? (b: number, c?: string): void => d() : e + // is determined by isParenthesizedArrowFunctionExpression to unambiguously + // be an arrow expression, so we allow a return type. + if (disallowReturnTypeInArrowFunction && hasReturnColon) { + // However, if the arrow function we were able to parse is followed by another colon + // as in: + // a ? (x): string => x : null + // Then allow the arrow function, and treat the second colon as terminating + // the conditional expression. + if (token() !== SyntaxKind.ColonToken) { + return undefined; + } + } + const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); return withJSDoc(finishNode(node, pos), hasJSDoc); } diff --git a/tests/baselines/reference/parserArrowFunctionExpression10.errors.txt b/tests/baselines/reference/parserArrowFunctionExpression10.errors.txt index 43cf9de267b85..0ee29b021a1ef 100644 --- a/tests/baselines/reference/parserArrowFunctionExpression10.errors.txt +++ b/tests/baselines/reference/parserArrowFunctionExpression10.errors.txt @@ -1,20 +1,17 @@ tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,1): error TS2304: Cannot find name 'a'. -tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,6): error TS2304: Cannot find name 'b'. +tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,11): error TS2304: Cannot find name 'c'. tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,17): error TS2304: Cannot find name 'd'. -tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,20): error TS1005: ';' expected. tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,27): error TS2304: Cannot find name 'f'. -==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts (5 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts (4 errors) ==== a ? (b) : c => (d) : e => f ~ !!! error TS2304: Cannot find name 'a'. - ~ -!!! error TS2304: Cannot find name 'b'. + ~ +!!! error TS2304: Cannot find name 'c'. ~ !!! error TS2304: Cannot find name 'd'. - ~ -!!! error TS1005: ';' expected. ~ !!! error TS2304: Cannot find name 'f'. \ No newline at end of file diff --git a/tests/baselines/reference/parserArrowFunctionExpression10.js b/tests/baselines/reference/parserArrowFunctionExpression10.js index 86e1e61bb0716..7681332637b4e 100644 --- a/tests/baselines/reference/parserArrowFunctionExpression10.js +++ b/tests/baselines/reference/parserArrowFunctionExpression10.js @@ -3,5 +3,4 @@ a ? (b) : c => (d) : e => f //// [parserArrowFunctionExpression10.js] -a ? (b) : function (c) { return (d); }; -(function (e) { return f; }); +a ? function (b) { return (d); } : function (e) { return f; }; diff --git a/tests/baselines/reference/parserArrowFunctionExpression10.symbols b/tests/baselines/reference/parserArrowFunctionExpression10.symbols index f30f0b3e3ca49..df391a0be345d 100644 --- a/tests/baselines/reference/parserArrowFunctionExpression10.symbols +++ b/tests/baselines/reference/parserArrowFunctionExpression10.symbols @@ -1,5 +1,6 @@ === tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts === a ? (b) : c => (d) : e => f ->c : Symbol(c, Decl(parserArrowFunctionExpression10.ts, 0, 9)) +>b : Symbol(b, Decl(parserArrowFunctionExpression10.ts, 0, 5)) +>c : Symbol(c) >e : Symbol(e, Decl(parserArrowFunctionExpression10.ts, 0, 20)) diff --git a/tests/baselines/reference/parserArrowFunctionExpression10.types b/tests/baselines/reference/parserArrowFunctionExpression10.types index 8ec7d69c29559..e4149fe4cbb5c 100644 --- a/tests/baselines/reference/parserArrowFunctionExpression10.types +++ b/tests/baselines/reference/parserArrowFunctionExpression10.types @@ -1,11 +1,9 @@ === tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts === a ? (b) : c => (d) : e => f ->a ? (b) : c => (d) : any +>a ? (b) : c => (d) : e => f : (b: any) => c >a : any ->(b) : any +>(b) : c => (d) : (b: any) => c >b : any ->c => (d) : (c: any) => any ->c : any >(d) : any >d : any >e => f : (e: any) => any diff --git a/tests/baselines/reference/parserArrowFunctionExpression15.js b/tests/baselines/reference/parserArrowFunctionExpression15.js new file mode 100644 index 0000000000000..a18efc84f0975 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression15.js @@ -0,0 +1,6 @@ +//// [parserArrowFunctionExpression15.ts] +false ? (param): string => param : null + + +//// [parserArrowFunctionExpression15.js] +false ? function (param) { return param; } : null; diff --git a/tests/baselines/reference/parserArrowFunctionExpression15.symbols b/tests/baselines/reference/parserArrowFunctionExpression15.symbols new file mode 100644 index 0000000000000..7cb354c7dc912 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression15.symbols @@ -0,0 +1,5 @@ +=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts === +false ? (param): string => param : null +>param : Symbol(param, Decl(parserArrowFunctionExpression15.ts, 0, 9)) +>param : Symbol(param, Decl(parserArrowFunctionExpression15.ts, 0, 9)) + diff --git a/tests/baselines/reference/parserArrowFunctionExpression15.types b/tests/baselines/reference/parserArrowFunctionExpression15.types new file mode 100644 index 0000000000000..4640763862112 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression15.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts === +false ? (param): string => param : null +>false ? (param): string => param : null : (param: any) => string +>false : false +>(param): string => param : (param: any) => string +>param : any +>param : any +>null : null + diff --git a/tests/baselines/reference/parserArrowFunctionExpression16.js b/tests/baselines/reference/parserArrowFunctionExpression16.js new file mode 100644 index 0000000000000..8d0404c91c853 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression16.js @@ -0,0 +1,6 @@ +//// [parserArrowFunctionExpression16.ts] +true ? false ? (param): string => param : null : null + + +//// [parserArrowFunctionExpression16.js] +true ? false ? function (param) { return param; } : null : null; diff --git a/tests/baselines/reference/parserArrowFunctionExpression16.symbols b/tests/baselines/reference/parserArrowFunctionExpression16.symbols new file mode 100644 index 0000000000000..f2a4ff04df134 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression16.symbols @@ -0,0 +1,5 @@ +=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts === +true ? false ? (param): string => param : null : null +>param : Symbol(param, Decl(parserArrowFunctionExpression16.ts, 0, 16)) +>param : Symbol(param, Decl(parserArrowFunctionExpression16.ts, 0, 16)) + diff --git a/tests/baselines/reference/parserArrowFunctionExpression16.types b/tests/baselines/reference/parserArrowFunctionExpression16.types new file mode 100644 index 0000000000000..fffd623adac0d --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression16.types @@ -0,0 +1,12 @@ +=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts === +true ? false ? (param): string => param : null : null +>true ? false ? (param): string => param : null : null : (param: any) => string +>true : true +>false ? (param): string => param : null : (param: any) => string +>false : false +>(param): string => param : (param: any) => string +>param : any +>param : any +>null : null +>null : null + diff --git a/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts b/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts new file mode 100644 index 0000000000000..3348d24bfebe4 --- /dev/null +++ b/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts @@ -0,0 +1 @@ +false ? (param): string => param : null diff --git a/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts b/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts new file mode 100644 index 0000000000000..9a19bfdb6cfc1 --- /dev/null +++ b/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts @@ -0,0 +1 @@ +true ? false ? (param): string => param : null : null