Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable JSX recovery hack when in unary expression context #53666

Merged
merged 2 commits into from Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/compiler/parser.ts
Expand Up @@ -5694,7 +5694,7 @@ namespace Parser {
// Just like in parseUpdateExpression, we need to avoid parsing type assertions when
// in JSX and we see an expression like "+ <foo> 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):
Expand Down Expand Up @@ -5921,7 +5921,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;
Expand Down Expand Up @@ -5978,7 +5978,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) {
Expand Down
@@ -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.

@@ -0,0 +1,7 @@
//// [a.js]
~< <


//// [a.js]
~< /> <
;
@@ -0,0 +1,4 @@
=== tests/cases/compiler/a.js ===

~< <

@@ -0,0 +1,9 @@
=== tests/cases/compiler/a.js ===
~< <
>~< < : boolean
>~< : number
>< : any
> : any

> : any

4 changes: 4 additions & 0 deletions tests/cases/compiler/parseJsxElementInUnaryExpressionCrash.ts
@@ -0,0 +1,4 @@
// @allowJs: true
// @outDir: ./out
// @filename: a.js
~< <