From cdf12f91c73c641738c2a3c57607986fb29321f3 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 30 Nov 2021 12:57:37 -0800 Subject: [PATCH] Fix parsing of parenthesized functions in conditional expressions (#46960) --- src/compiler/parser.ts | 3 ++- ...izedVariableAndParenthesizedFunctionInTernary.js | 8 ++++++++ ...ariableAndParenthesizedFunctionInTernary.symbols | 8 ++++++++ ...dVariableAndParenthesizedFunctionInTernary.types | 13 +++++++++++++ ...izedVariableAndParenthesizedFunctionInTernary.ts | 2 ++ 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.js create mode 100644 tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.symbols create mode 100644 tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.types create mode 100644 tests/cases/conformance/parser/ecmascript5/parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6bb5d0aec31b9..9ca4828fec111 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4539,9 +4539,10 @@ namespace ts { // - "(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. // - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type. + // - "a ? (b): (function() {})" as well, but inside of a parenthesized type. // // So we need just a bit of lookahead to ensure that it can only be a signature. - const hasJSDocFunctionType = type && isJSDocFunctionType(type); + const hasJSDocFunctionType = type && (isJSDocFunctionType(type) || isParenthesizedTypeNode(type) && isJSDocFunctionType(type.type)); if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) { // Returning undefined here will cause our caller to rewind to where we started from. return undefined; diff --git a/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.js b/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.js new file mode 100644 index 0000000000000..2aa4a3989b9fa --- /dev/null +++ b/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.js @@ -0,0 +1,8 @@ +//// [parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts] +let a: any; +const c = true ? (a) : (function() {}); + + +//// [parserParenthesizedVariableAndParenthesizedFunctionInTernary.js] +var a; +var c = true ? (a) : (function () { }); diff --git a/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.symbols b/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.symbols new file mode 100644 index 0000000000000..9e2db3a1f667b --- /dev/null +++ b/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.symbols @@ -0,0 +1,8 @@ +=== tests/cases/conformance/parser/ecmascript5/parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts === +let a: any; +>a : Symbol(a, Decl(parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts, 0, 3)) + +const c = true ? (a) : (function() {}); +>c : Symbol(c, Decl(parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts, 1, 5)) +>a : Symbol(a, Decl(parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts, 0, 3)) + diff --git a/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.types b/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.types new file mode 100644 index 0000000000000..5d9ee98ad924a --- /dev/null +++ b/tests/baselines/reference/parserParenthesizedVariableAndParenthesizedFunctionInTernary.types @@ -0,0 +1,13 @@ +=== tests/cases/conformance/parser/ecmascript5/parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts === +let a: any; +>a : any + +const c = true ? (a) : (function() {}); +>c : any +>true ? (a) : (function() {}) : any +>true : true +>(a) : any +>a : any +>(function() {}) : () => void +>function() {} : () => void + diff --git a/tests/cases/conformance/parser/ecmascript5/parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts b/tests/cases/conformance/parser/ecmascript5/parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts new file mode 100644 index 0000000000000..6b22d3dd12cdf --- /dev/null +++ b/tests/cases/conformance/parser/ecmascript5/parserParenthesizedVariableAndParenthesizedFunctionInTernary.ts @@ -0,0 +1,2 @@ +let a: any; +const c = true ? (a) : (function() {});