From 0ef9e8eac9cedfaadc3f9072313cdea78472a2d5 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 9 Feb 2023 11:34:47 -0800 Subject: [PATCH] Ensure we treat "type assertions" as JSX within a unary expression (#52667) --- src/compiler/parser.ts | 6 +++++ ...ExpressionNoTypeAssertionInJsx1.errors.txt | 15 ++++++++++++ ...aryExpressionNoTypeAssertionInJsx1.symbols | 7 ++++++ ...UnaryExpressionNoTypeAssertionInJsx1.types | 13 ++++++++++ ...ExpressionNoTypeAssertionInJsx2.errors.txt | 15 ++++++++++++ ...aryExpressionNoTypeAssertionInJsx2.symbols | 7 ++++++ ...UnaryExpressionNoTypeAssertionInJsx2.types | 10 ++++++++ ...ExpressionNoTypeAssertionInJsx3.errors.txt | 15 ++++++++++++ ...aryExpressionNoTypeAssertionInJsx3.symbols | 8 +++++++ ...UnaryExpressionNoTypeAssertionInJsx3.types | 14 +++++++++++ ...ExpressionNoTypeAssertionInJsx4.errors.txt | 24 +++++++++++++++++++ ...rseUnaryExpressionNoTypeAssertionInJsx4.js | 14 +++++++++++ ...aryExpressionNoTypeAssertionInJsx4.symbols | 10 ++++++++ ...UnaryExpressionNoTypeAssertionInJsx4.types | 20 ++++++++++++++++ ...rseUnaryExpressionNoTypeAssertionInJsx1.ts | 7 ++++++ ...rseUnaryExpressionNoTypeAssertionInJsx2.ts | 7 ++++++ ...rseUnaryExpressionNoTypeAssertionInJsx3.ts | 7 ++++++ ...rseUnaryExpressionNoTypeAssertionInJsx4.ts | 8 +++++++ 18 files changed, 207 insertions(+) create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.errors.txt create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.symbols create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.types create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.errors.txt create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.symbols create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.types create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.errors.txt create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.symbols create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.types create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.errors.txt create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.js create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.symbols create mode 100644 tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.types create mode 100644 tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts create mode 100644 tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx2.ts create mode 100644 tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx3.ts create mode 100644 tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx4.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0baf8b65bc4..4763040626b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5648,6 +5648,11 @@ namespace Parser { case SyntaxKind.VoidKeyword: return parseVoidExpression(); case SyntaxKind.LessThanToken: + // 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); + } // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): // < type > UnaryExpression @@ -6163,6 +6168,7 @@ namespace Parser { } function parseTypeAssertion(): TypeAssertion { + Debug.assert(scriptKind === ScriptKind.TS, "Type assertions should never be parsed outside of TS; they should either be comparisons or JSX."); const pos = getNodePos(); parseExpected(SyntaxKind.LessThanToken); const type = parseType(); diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.errors.txt b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.errors.txt new file mode 100644 index 00000000000..6a77ea5512e --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/index.js(2,13): error TS17004: Cannot use JSX unless the '--jsx' flag is provided. +tests/cases/compiler/index.js(2,14): error TS17008: JSX element 'number' has no corresponding closing tag. +tests/cases/compiler/index.js(3,1): error TS1005: ' x; + ~~~~~~~~ +!!! error TS17004: Cannot use JSX unless the '--jsx' flag is provided. + ~~~~~~ +!!! error TS17008: JSX element 'number' has no corresponding closing tag. + + +!!! error TS1005: 'x : Symbol(x, Decl(index.js, 0, 5)) + +const y = + x; +>y : Symbol(y, Decl(index.js, 1, 5)) + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.types b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.types new file mode 100644 index 00000000000..e2d8b7e2fec --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx1.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/index.js === +const x = "oops"; +>x : "oops" +>"oops" : "oops" + +const y = + x; +>y : number +>+ x; : number +> x; : any +>number : any + +> : any + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.errors.txt b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.errors.txt new file mode 100644 index 00000000000..b1acc4a4774 --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/index.js(2,12): error TS17014: JSX fragment has no corresponding closing tag. +tests/cases/compiler/index.js(2,13): error TS17004: Cannot use JSX unless the '--jsx' flag is provided. +tests/cases/compiler/index.js(3,1): error TS1005: ' x; + ~~~ +!!! error TS17014: JSX fragment has no corresponding closing tag. + ~~ +!!! error TS17004: Cannot use JSX unless the '--jsx' flag is provided. + + +!!! error TS1005: 'x : Symbol(x, Decl(index.js, 0, 5)) + +const y = + <> x; +>y : Symbol(y, Decl(index.js, 1, 5)) + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.types b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.types new file mode 100644 index 00000000000..b8a8ef32d64 --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx2.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/index.js === +const x = "oops"; +>x : "oops" +>"oops" : "oops" + +const y = + <> x; +>y : number +>+ <> x; : number +><> x; : any + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.errors.txt b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.errors.txt new file mode 100644 index 00000000000..132f825fe40 --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/index.js(2,13): error TS17004: Cannot use JSX unless the '--jsx' flag is provided. +tests/cases/compiler/index.js(2,14): error TS1003: Identifier expected. +tests/cases/compiler/index.js(2,14): error TS2365: Operator '>' cannot be applied to types 'number' and 'string'. + + +==== tests/cases/compiler/index.js (3 errors) ==== + const x = "oops"; + const y = + <1234> x; + ~ +!!! error TS17004: Cannot use JSX unless the '--jsx' flag is provided. + ~~~~ +!!! error TS1003: Identifier expected. + ~~~~~~~ +!!! error TS2365: Operator '>' cannot be applied to types 'number' and 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.symbols b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.symbols new file mode 100644 index 00000000000..a8c0e88d945 --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/index.js === +const x = "oops"; +>x : Symbol(x, Decl(index.js, 0, 5)) + +const y = + <1234> x; +>y : Symbol(y, Decl(index.js, 1, 5)) +>x : Symbol(x, Decl(index.js, 0, 5)) + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.types b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.types new file mode 100644 index 00000000000..9cdbabb588e --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx3.types @@ -0,0 +1,14 @@ +=== tests/cases/compiler/index.js === +const x = "oops"; +>x : "oops" +>"oops" : "oops" + +const y = + <1234> x; +>y : number +>+ < : number +>< : any +> : any +>1234> x : boolean +>1234 : 1234 +>x : "oops" + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.errors.txt b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.errors.txt new file mode 100644 index 00000000000..24710242160 --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.errors.txt @@ -0,0 +1,24 @@ +tests/cases/compiler/index.tsx(3,14): error TS17008: JSX element 'number' has no corresponding closing tag. +tests/cases/compiler/index.tsx(4,13): error TS17014: JSX fragment has no corresponding closing tag. +tests/cases/compiler/index.tsx(5,14): error TS1003: Identifier expected. +tests/cases/compiler/index.tsx(5,18): error TS1382: Unexpected token. Did you mean `{'>'}` or `>`? +tests/cases/compiler/index.tsx(6,1): error TS1005: ' x; + ~~~~~~ +!!! error TS17008: JSX element 'number' has no corresponding closing tag. + const b = + <> x; + ~~ +!!! error TS17014: JSX fragment has no corresponding closing tag. + const c = + <1234> x; + ~~~~ +!!! error TS1003: Identifier expected. + ~ +!!! error TS1382: Unexpected token. Did you mean `{'>'}` or `>`? + + +!!! error TS1005: ' x; +const b = + <> x; +const c = + <1234> x; + + +//// [index.jsx] +var x = "oops"; +var a = + x; +const b = + <> x; +const c = + < />1234> x; +; diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.symbols b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.symbols new file mode 100644 index 00000000000..50a8c1e513c --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/index.tsx === +const x = "oops"; +>x : Symbol(x, Decl(index.tsx, 0, 5)) + +const a = + x; +>a : Symbol(a, Decl(index.tsx, 2, 5)) + +const b = + <> x; +const c = + <1234> x; + diff --git a/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.types b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.types new file mode 100644 index 00000000000..e0e0c0d4d64 --- /dev/null +++ b/tests/baselines/reference/parseUnaryExpressionNoTypeAssertionInJsx4.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/index.tsx === +const x = "oops"; +>x : "oops" +>"oops" : "oops" + +const a = + x; +>a : number +>+ x;const b = + <> x;const c = + <1234> x; : number +> x;const b = + <> x;const c = + <1234> x; : any +>number : any + +const b = + <> x; +><> x;const c = + <1234> x; : any + +const c = + <1234> x; +>< : any +> : any + +> : any + diff --git a/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts new file mode 100644 index 00000000000..1c9be1bd45a --- /dev/null +++ b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts @@ -0,0 +1,7 @@ +// @allowJs: true +// @noEmit: true +// @checkJs: true +// @filename: index.js + +const x = "oops"; +const y = + x; diff --git a/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx2.ts b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx2.ts new file mode 100644 index 00000000000..1b6b86d830d --- /dev/null +++ b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx2.ts @@ -0,0 +1,7 @@ +// @allowJs: true +// @noEmit: true +// @checkJs: true +// @filename: index.js + +const x = "oops"; +const y = + <> x; diff --git a/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx3.ts b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx3.ts new file mode 100644 index 00000000000..09407f0a85f --- /dev/null +++ b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx3.ts @@ -0,0 +1,7 @@ +// @allowJs: true +// @noEmit: true +// @checkJs: true +// @filename: index.js + +const x = "oops"; +const y = + <1234> x; diff --git a/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx4.ts b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx4.ts new file mode 100644 index 00000000000..4f892516d10 --- /dev/null +++ b/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx4.ts @@ -0,0 +1,8 @@ +// @filename: index.tsx +// @jsx: preserve + +const x = "oops"; + +const a = + x; +const b = + <> x; +const c = + <1234> x;