Skip to content

Commit bebb6d0

Browse files
authored
Disable JSX recovery hack when in unary expression context (#53666)
1 parent a720ba9 commit bebb6d0

11 files changed

+71
-3
lines changed

src/compiler/parser.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5694,7 +5694,7 @@ namespace Parser {
56945694
// Just like in parseUpdateExpression, we need to avoid parsing type assertions when
56955695
// in JSX and we see an expression like "+ <foo> bar".
56965696
if (languageVariant === LanguageVariant.JSX) {
5697-
return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);
5697+
return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, /*topInvalidNodePosition*/ undefined, /*openingTag*/ undefined, /*mustBeUnary*/ true);
56985698
}
56995699
// This is modified UnaryExpression grammar in TypeScript
57005700
// UnaryExpression (modified):
@@ -5921,7 +5921,7 @@ namespace Parser {
59215921
return finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos);
59225922
}
59235923

5924-
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment {
5924+
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment, mustBeUnary = false): JsxElement | JsxSelfClosingElement | JsxFragment {
59255925
const pos = getNodePos();
59265926
const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);
59275927
let result: JsxElement | JsxSelfClosingElement | JsxFragment;
@@ -5978,7 +5978,9 @@ namespace Parser {
59785978
// does less damage and we can report a better error.
59795979
// Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
59805980
// of one sort or another.
5981-
if (inExpressionContext && token() === SyntaxKind.LessThanToken) {
5981+
// If we are in a unary context, we can't do this recovery; the binary expression we return here is not
5982+
// a valid UnaryExpression and will cause problems later.
5983+
if (!mustBeUnary && inExpressionContext && token() === SyntaxKind.LessThanToken) {
59825984
const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition;
59835985
const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos));
59845986
if (invalidElement) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/a.js(1,4): error TS1003: Identifier expected.
2+
tests/cases/compiler/a.js(1,5): error TS1109: Expression expected.
3+
4+
5+
==== tests/cases/compiler/a.js (2 errors) ====
6+
~< <
7+
~
8+
!!! error TS1003: Identifier expected.
9+
10+
!!! error TS1109: Expression expected.
11+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [a.js]
2+
~< <
3+
4+
5+
//// [a.js]
6+
~< /> <
7+
;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
=== tests/cases/compiler/a.js ===
2+
3+
~< <
4+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/a.js ===
2+
~< <
3+
>~< < : boolean
4+
>~< : number
5+
>< : any
6+
> : any
7+
8+
> : any
9+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests/cases/compiler/a.js(1,9): error TS1109: Expression expected.
2+
3+
4+
==== tests/cases/compiler/a.js (1 errors) ====
5+
~<></> <
6+
7+
!!! error TS1109: Expression expected.
8+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [a.js]
2+
~<></> <
3+
4+
5+
//// [a.js]
6+
~<></> <
7+
;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
=== tests/cases/compiler/a.js ===
2+
3+
~<></> <
4+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/compiler/a.js ===
2+
~<></> <
3+
>~<></> < : boolean
4+
>~<></> : number
5+
><></> : any
6+
7+
> : any
8+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @allowJs: true
2+
// @outDir: ./out
3+
// @filename: a.js
4+
~< <
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @allowJs: true
2+
// @outDir: ./out
3+
// @filename: a.js
4+
~<></> <

0 commit comments

Comments
 (0)