diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index be81d789c57d0..cd0d806794c31 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5684,7 +5684,7 @@ namespace Parser { // Just like in parseUpdateExpression, we need to avoid parsing type assertions when // in JSX and we see an expression like "+ bar". if (languageVariant === LanguageVariant.JSX) { - return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, /*topInvalidNodePosition*/ undefined, /*openingTag*/ undefined, /*mustBeUnary*/ true); } // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): @@ -5911,7 +5911,7 @@ namespace Parser { return finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos); } - function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment { + function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment, mustBeUnary = false): JsxElement | JsxSelfClosingElement | JsxFragment { const pos = getNodePos(); const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); let result: JsxElement | JsxSelfClosingElement | JsxFragment; @@ -5968,7 +5968,9 @@ namespace Parser { // does less damage and we can report a better error. // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios // of one sort or another. - if (inExpressionContext && token() === SyntaxKind.LessThanToken) { + // If we are in a unary context, we can't do this recovery; the binary expression we return here is not + // a valid UnaryExpression and will cause problems later. + if (!mustBeUnary && inExpressionContext && token() === SyntaxKind.LessThanToken) { const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition; const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos)); if (invalidElement) { diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.errors.txt b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.errors.txt new file mode 100644 index 0000000000000..6f638b4a2230f --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/a.js(1,4): error TS1003: Identifier expected. +tests/cases/compiler/a.js(1,5): error TS1109: Expression expected. + + +==== tests/cases/compiler/a.js (2 errors) ==== + ~< < + ~ +!!! error TS1003: Identifier expected. + +!!! error TS1109: Expression expected. + \ No newline at end of file diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.js b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.js new file mode 100644 index 0000000000000..64357a51dc64e --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.js @@ -0,0 +1,7 @@ +//// [a.js] +~< < + + +//// [a.js] +~< /> < +; diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.symbols b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.symbols new file mode 100644 index 0000000000000..e6ed11e193527 --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.symbols @@ -0,0 +1,4 @@ +=== tests/cases/compiler/a.js === + +~< < + diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.types b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.types new file mode 100644 index 0000000000000..ec5c50b31c5b0 --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash1.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/a.js === +~< < +>~< < : boolean +>~< : number +>< : any +> : any + +> : any + diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.errors.txt b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.errors.txt new file mode 100644 index 0000000000000..4ae236bce12a4 --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.errors.txt @@ -0,0 +1,8 @@ +tests/cases/compiler/a.js(1,9): error TS1109: Expression expected. + + +==== tests/cases/compiler/a.js (1 errors) ==== + ~<> < + +!!! error TS1109: Expression expected. + \ No newline at end of file diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.js b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.js new file mode 100644 index 0000000000000..0a9f06793a66f --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.js @@ -0,0 +1,7 @@ +//// [a.js] +~<> < + + +//// [a.js] +~<> < +; diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.symbols b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.symbols new file mode 100644 index 0000000000000..d6832b40cd279 --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.symbols @@ -0,0 +1,4 @@ +=== tests/cases/compiler/a.js === + +~<> < + diff --git a/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.types b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.types new file mode 100644 index 0000000000000..0c0fce49f7382 --- /dev/null +++ b/tests/baselines/reference/parseJsxElementInUnaryExpressionNoCrash2.types @@ -0,0 +1,8 @@ +=== tests/cases/compiler/a.js === +~<> < +>~<> < : boolean +>~<> : number +><> : any + +> : any + diff --git a/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash1.ts b/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash1.ts new file mode 100644 index 0000000000000..177022396f4ad --- /dev/null +++ b/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash1.ts @@ -0,0 +1,4 @@ +// @allowJs: true +// @outDir: ./out +// @filename: a.js +~< < diff --git a/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash2.ts b/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash2.ts new file mode 100644 index 0000000000000..0fbf4b3eb2abb --- /dev/null +++ b/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash2.ts @@ -0,0 +1,4 @@ +// @allowJs: true +// @outDir: ./out +// @filename: a.js +~<> <