From b6eb9904f6b5e62a4aceee9a14d4ddb1c7536d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 22 Oct 2025 19:47:10 +0200 Subject: [PATCH 1/2] Fixed a crash when parsing invalid decorator on await expression --- src/compiler/parser.ts | 4 +++- .../reference/decoratorOnAwait.errors.txt | 11 +++++++++++ tests/baselines/reference/decoratorOnAwait.js | 12 ++++++++++++ .../reference/decoratorOnAwait.symbols | 15 +++++++++++++++ .../baselines/reference/decoratorOnAwait.types | 17 +++++++++++++++++ .../decorators/invalid/decoratorOnAwait.ts | 4 ++++ 6 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/decoratorOnAwait.errors.txt create mode 100644 tests/baselines/reference/decoratorOnAwait.js create mode 100644 tests/baselines/reference/decoratorOnAwait.symbols create mode 100644 tests/baselines/reference/decoratorOnAwait.types create mode 100644 tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d641cbd4b65e7..5fddb9eb9d10a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -7677,7 +7677,9 @@ namespace Parser { flags |= NodeFlags.Using; break; case SyntaxKind.AwaitKeyword: - Debug.assert(isAwaitUsingDeclaration()); + if (!isAwaitUsingDeclaration()) { + break; + } flags |= NodeFlags.AwaitUsing; nextToken(); break; diff --git a/tests/baselines/reference/decoratorOnAwait.errors.txt b/tests/baselines/reference/decoratorOnAwait.errors.txt new file mode 100644 index 0000000000000..2b81fa95658e1 --- /dev/null +++ b/tests/baselines/reference/decoratorOnAwait.errors.txt @@ -0,0 +1,11 @@ +decoratorOnAwait.ts(4,7): error TS1134: Variable declaration expected. + + +==== decoratorOnAwait.ts (1 errors) ==== + declare function dec(target: T): T; + + @dec + await 1 + ~ +!!! error TS1134: Variable declaration expected. + \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnAwait.js b/tests/baselines/reference/decoratorOnAwait.js new file mode 100644 index 0000000000000..5d6edcb5701b8 --- /dev/null +++ b/tests/baselines/reference/decoratorOnAwait.js @@ -0,0 +1,12 @@ +//// [tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts] //// + +//// [decoratorOnAwait.ts] +declare function dec(target: T): T; + +@dec +await 1 + + +//// [decoratorOnAwait.js] +var ; +1; diff --git a/tests/baselines/reference/decoratorOnAwait.symbols b/tests/baselines/reference/decoratorOnAwait.symbols new file mode 100644 index 0000000000000..a2c9ac6a3a10f --- /dev/null +++ b/tests/baselines/reference/decoratorOnAwait.symbols @@ -0,0 +1,15 @@ +//// [tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts] //// + +=== decoratorOnAwait.ts === +declare function dec(target: T): T; +>dec : Symbol(dec, Decl(decoratorOnAwait.ts, 0, 0)) +>T : Symbol(T, Decl(decoratorOnAwait.ts, 0, 21)) +>target : Symbol(target, Decl(decoratorOnAwait.ts, 0, 24)) +>T : Symbol(T, Decl(decoratorOnAwait.ts, 0, 21)) +>T : Symbol(T, Decl(decoratorOnAwait.ts, 0, 21)) + +@dec +>dec : Symbol(dec, Decl(decoratorOnAwait.ts, 0, 0)) + +await 1 + diff --git a/tests/baselines/reference/decoratorOnAwait.types b/tests/baselines/reference/decoratorOnAwait.types new file mode 100644 index 0000000000000..123933e7bb97b --- /dev/null +++ b/tests/baselines/reference/decoratorOnAwait.types @@ -0,0 +1,17 @@ +//// [tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts] //// + +=== decoratorOnAwait.ts === +declare function dec(target: T): T; +>dec : (target: T) => T +> : ^ ^^ ^^ ^^^^^ +>target : T +> : ^ + +@dec +>dec : (target: T) => T +> : ^ ^^ ^^ ^^^^^ + +await 1 +>1 : 1 +> : ^ + diff --git a/tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts b/tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts new file mode 100644 index 0000000000000..71fc65e34a036 --- /dev/null +++ b/tests/cases/conformance/decorators/invalid/decoratorOnAwait.ts @@ -0,0 +1,4 @@ +declare function dec(target: T): T; + +@dec +await 1 From 97352731fd5ccb37a67a61c6284c4d1471e1bbb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 22 Oct 2025 19:54:24 +0200 Subject: [PATCH 2/2] better recovery --- src/compiler/parser.ts | 23 +++++++++-------- .../reference/decoratorOnAwait.errors.txt | 6 ++--- tests/baselines/reference/decoratorOnAwait.js | 3 +-- .../reference/decoratorOnAwait.types | 2 ++ .../reference/decoratorOnUsing.errors.txt | 14 +++++++++++ tests/baselines/reference/decoratorOnUsing.js | 16 ++++++++++++ .../reference/decoratorOnUsing.symbols | 21 ++++++++++++++++ .../reference/decoratorOnUsing.types | 25 +++++++++++++++++++ .../decorators/invalid/decoratorOnUsing.ts | 8 ++++++ 9 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 tests/baselines/reference/decoratorOnUsing.errors.txt create mode 100644 tests/baselines/reference/decoratorOnUsing.js create mode 100644 tests/baselines/reference/decoratorOnUsing.symbols create mode 100644 tests/baselines/reference/decoratorOnUsing.types create mode 100644 tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5fddb9eb9d10a..68133ac5f1e40 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -7505,7 +7505,11 @@ namespace Parser { case SyntaxKind.LetKeyword: case SyntaxKind.ConstKeyword: case SyntaxKind.UsingKeyword: + return parseVariableStatement(pos, hasJSDoc, modifiersIn); case SyntaxKind.AwaitKeyword: + if (!isAwaitUsingDeclaration()) { + break; + } return parseVariableStatement(pos, hasJSDoc, modifiersIn); case SyntaxKind.FunctionKeyword: return parseFunctionDeclaration(pos, hasJSDoc, modifiersIn); @@ -7534,17 +7538,16 @@ namespace Parser { default: return parseExportDeclaration(pos, hasJSDoc, modifiersIn); } - default: - if (modifiersIn) { - // We reached this point because we encountered decorators and/or modifiers and assumed a declaration - // would follow. For recovery and error reporting purposes, return an incomplete declaration. - const missing = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); - setTextRangePos(missing, pos); - (missing as Mutable).modifiers = modifiersIn; - return missing; - } - return undefined!; // TODO: GH#18217 } + if (modifiersIn) { + // We reached this point because we encountered decorators and/or modifiers and assumed a declaration + // would follow. For recovery and error reporting purposes, return an incomplete declaration. + const missing = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + setTextRangePos(missing, pos); + (missing as Mutable).modifiers = modifiersIn; + return missing; + } + return undefined!; // TODO: GH#18217 } function nextTokenIsStringLiteral() { diff --git a/tests/baselines/reference/decoratorOnAwait.errors.txt b/tests/baselines/reference/decoratorOnAwait.errors.txt index 2b81fa95658e1..72a64f3c7d865 100644 --- a/tests/baselines/reference/decoratorOnAwait.errors.txt +++ b/tests/baselines/reference/decoratorOnAwait.errors.txt @@ -1,11 +1,11 @@ -decoratorOnAwait.ts(4,7): error TS1134: Variable declaration expected. +decoratorOnAwait.ts(3,5): error TS1146: Declaration expected. ==== decoratorOnAwait.ts (1 errors) ==== declare function dec(target: T): T; @dec + +!!! error TS1146: Declaration expected. await 1 - ~ -!!! error TS1134: Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnAwait.js b/tests/baselines/reference/decoratorOnAwait.js index 5d6edcb5701b8..c8a0546e388ff 100644 --- a/tests/baselines/reference/decoratorOnAwait.js +++ b/tests/baselines/reference/decoratorOnAwait.js @@ -8,5 +8,4 @@ await 1 //// [decoratorOnAwait.js] -var ; -1; +await 1; diff --git a/tests/baselines/reference/decoratorOnAwait.types b/tests/baselines/reference/decoratorOnAwait.types index 123933e7bb97b..f5a3ec4681d42 100644 --- a/tests/baselines/reference/decoratorOnAwait.types +++ b/tests/baselines/reference/decoratorOnAwait.types @@ -12,6 +12,8 @@ declare function dec(target: T): T; > : ^ ^^ ^^ ^^^^^ await 1 +>await 1 : 1 +> : ^ >1 : 1 > : ^ diff --git a/tests/baselines/reference/decoratorOnUsing.errors.txt b/tests/baselines/reference/decoratorOnUsing.errors.txt new file mode 100644 index 0000000000000..1861fa34a32e8 --- /dev/null +++ b/tests/baselines/reference/decoratorOnUsing.errors.txt @@ -0,0 +1,14 @@ +decoratorOnUsing.ts(4,7): error TS1134: Variable declaration expected. + + +==== decoratorOnUsing.ts (1 errors) ==== + declare function dec(target: T): T; + + @dec + using 1 + ~ +!!! error TS1134: Variable declaration expected. + + @dec + using x + \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnUsing.js b/tests/baselines/reference/decoratorOnUsing.js new file mode 100644 index 0000000000000..47b470c658d9b --- /dev/null +++ b/tests/baselines/reference/decoratorOnUsing.js @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts] //// + +//// [decoratorOnUsing.ts] +declare function dec(target: T): T; + +@dec +using 1 + +@dec +using x + + +//// [decoratorOnUsing.js] +using ; +1; +using x; diff --git a/tests/baselines/reference/decoratorOnUsing.symbols b/tests/baselines/reference/decoratorOnUsing.symbols new file mode 100644 index 0000000000000..a173c7e318502 --- /dev/null +++ b/tests/baselines/reference/decoratorOnUsing.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts] //// + +=== decoratorOnUsing.ts === +declare function dec(target: T): T; +>dec : Symbol(dec, Decl(decoratorOnUsing.ts, 0, 0)) +>T : Symbol(T, Decl(decoratorOnUsing.ts, 0, 21)) +>target : Symbol(target, Decl(decoratorOnUsing.ts, 0, 24)) +>T : Symbol(T, Decl(decoratorOnUsing.ts, 0, 21)) +>T : Symbol(T, Decl(decoratorOnUsing.ts, 0, 21)) + +@dec +>dec : Symbol(dec, Decl(decoratorOnUsing.ts, 0, 0)) + +using 1 + +@dec +>dec : Symbol(dec, Decl(decoratorOnUsing.ts, 0, 0)) + +using x +>x : Symbol(x, Decl(decoratorOnUsing.ts, 6, 5)) + diff --git a/tests/baselines/reference/decoratorOnUsing.types b/tests/baselines/reference/decoratorOnUsing.types new file mode 100644 index 0000000000000..cb108be89851e --- /dev/null +++ b/tests/baselines/reference/decoratorOnUsing.types @@ -0,0 +1,25 @@ +//// [tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts] //// + +=== decoratorOnUsing.ts === +declare function dec(target: T): T; +>dec : (target: T) => T +> : ^ ^^ ^^ ^^^^^ +>target : T +> : ^ + +@dec +>dec : (target: T) => T +> : ^ ^^ ^^ ^^^^^ + +using 1 +>1 : 1 +> : ^ + +@dec +>dec : (target: T) => T +> : ^ ^^ ^^ ^^^^^ + +using x +>x : any +> : ^^^ + diff --git a/tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts b/tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts new file mode 100644 index 0000000000000..815da8de4de27 --- /dev/null +++ b/tests/cases/conformance/decorators/invalid/decoratorOnUsing.ts @@ -0,0 +1,8 @@ +// @target: esnext +declare function dec(target: T): T; + +@dec +using 1 + +@dec +using x