From 3c91e790cbdf71d4e2ea879647585fcfe07c9280 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 07:52:52 +0000 Subject: [PATCH 1/3] Initial plan From 872c61d5c5b33eef0b8445d80dcb84fd41b69d31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 08:07:09 +0000 Subject: [PATCH 2/3] Add test for await object literal parsing issue Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/e349c6c9-f922-4939-b9e7-b51399e84279 Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- internal/parser/debug_test.go | 38 +++++++++++++++++++ .../cases/compiler/awaitObjectLiteral.ts | 6 +++ 2 files changed, 44 insertions(+) create mode 100644 internal/parser/debug_test.go create mode 100644 testdata/tests/cases/compiler/awaitObjectLiteral.ts diff --git a/internal/parser/debug_test.go b/internal/parser/debug_test.go new file mode 100644 index 00000000000..fda3b772363 --- /dev/null +++ b/internal/parser/debug_test.go @@ -0,0 +1,38 @@ +package parser + +import ( +"fmt" +"testing" +"github.com/microsoft/typescript-go/internal/ast" +"github.com/microsoft/typescript-go/internal/core" +) + +func TestDebugAwaitParsing(t *testing.T) { +source := "export {}\nconst foo = await { bar: 42 }\n" +opts := ast.SourceFileParseOptions{ +FileName: "/test.ts", +} +file := ParseSourceFile(opts, source, core.ScriptKindTS) + +fmt.Println("Statements:", len(file.Statements.Nodes)) +for i, stmt := range file.Statements.Nodes { +fmt.Printf(" [%d] Kind=%v Flags=%v Pos=%d End=%d\n", i, stmt.Kind, stmt.Flags, stmt.Pos(), stmt.End()) +if stmt.Kind == ast.KindVariableStatement { +vs := stmt.AsVariableStatement() +dl := vs.DeclarationList.AsVariableDeclarationList() +fmt.Printf(" DeclarationList declarations: %d\n", len(dl.Declarations.Nodes)) +for j, decl := range dl.Declarations.Nodes { +vd := decl.AsVariableDeclaration() +fmt.Printf(" [%d] Name=%v\n", j, vd.Name().Kind) +if vd.Initializer != nil { +fmt.Printf(" InitKind=%v\n", vd.Initializer.Kind) +} +} +} +} +fmt.Println("\nDiagnostics:", len(file.Diagnostics())) +for _, d := range file.Diagnostics() { +fmt.Printf(" pos=%d\n", d.Pos()) +} +fmt.Println("\nExternalModuleIndicator:", file.ExternalModuleIndicator != nil) +} diff --git a/testdata/tests/cases/compiler/awaitObjectLiteral.ts b/testdata/tests/cases/compiler/awaitObjectLiteral.ts new file mode 100644 index 00000000000..b3413913656 --- /dev/null +++ b/testdata/tests/cases/compiler/awaitObjectLiteral.ts @@ -0,0 +1,6 @@ +// @target: esnext +// @module: esnext + +// @filename: fileA.ts +export {} +const foo = await { bar: 42 } From 36f5a7ad96424a3bec4e9c6adb83a0a408ec300a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 08:20:23 +0000 Subject: [PATCH 3/3] Fix reparseTopLevelAwait diagnostic slicing bug The diagnostic slicing in reparseTopLevelAwait used savedParseDiagnostics[:diagnosticStart] when it should have used savedParseDiagnostics[diagnosticStart:] to find the end of the diagnostic range. This caused initial parse diagnostics to leak through even after a successful reparse with await context. Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/e349c6c9-f922-4939-b9e7-b51399e84279 Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- internal/parser/debug_test.go | 38 ------------------ internal/parser/parser.go | 2 +- .../reference/compiler/awaitObjectLiteral.js | 15 +++++++ .../compiler/awaitObjectLiteral.symbols | 14 +++++++ .../compiler/awaitObjectLiteral.types | 21 ++++++++++ .../reachabilityChecksNoCrash1.errors.txt | 8 +--- ...reachabilityChecksNoCrash1.errors.txt.diff | 39 +------------------ .../cases/compiler/awaitObjectLiteral.ts | 3 ++ 8 files changed, 57 insertions(+), 83 deletions(-) delete mode 100644 internal/parser/debug_test.go create mode 100644 testdata/baselines/reference/compiler/awaitObjectLiteral.js create mode 100644 testdata/baselines/reference/compiler/awaitObjectLiteral.symbols create mode 100644 testdata/baselines/reference/compiler/awaitObjectLiteral.types diff --git a/internal/parser/debug_test.go b/internal/parser/debug_test.go deleted file mode 100644 index fda3b772363..00000000000 --- a/internal/parser/debug_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package parser - -import ( -"fmt" -"testing" -"github.com/microsoft/typescript-go/internal/ast" -"github.com/microsoft/typescript-go/internal/core" -) - -func TestDebugAwaitParsing(t *testing.T) { -source := "export {}\nconst foo = await { bar: 42 }\n" -opts := ast.SourceFileParseOptions{ -FileName: "/test.ts", -} -file := ParseSourceFile(opts, source, core.ScriptKindTS) - -fmt.Println("Statements:", len(file.Statements.Nodes)) -for i, stmt := range file.Statements.Nodes { -fmt.Printf(" [%d] Kind=%v Flags=%v Pos=%d End=%d\n", i, stmt.Kind, stmt.Flags, stmt.Pos(), stmt.End()) -if stmt.Kind == ast.KindVariableStatement { -vs := stmt.AsVariableStatement() -dl := vs.DeclarationList.AsVariableDeclarationList() -fmt.Printf(" DeclarationList declarations: %d\n", len(dl.Declarations.Nodes)) -for j, decl := range dl.Declarations.Nodes { -vd := decl.AsVariableDeclaration() -fmt.Printf(" [%d] Name=%v\n", j, vd.Name().Kind) -if vd.Initializer != nil { -fmt.Printf(" InitKind=%v\n", vd.Initializer.Kind) -} -} -} -} -fmt.Println("\nDiagnostics:", len(file.Diagnostics())) -for _, d := range file.Diagnostics() { -fmt.Printf(" pos=%d\n", d.Pos()) -} -fmt.Println("\nExternalModuleIndicator:", file.ExternalModuleIndicator != nil) -} diff --git a/internal/parser/parser.go b/internal/parser/parser.go index f0ccfc3f9ea..af0dbcc1669 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -532,7 +532,7 @@ func (p *Parser) reparseTopLevelAwait(sourceFile *ast.SourceFile) *ast.Node { }) var diagnosticEnd int if diagnosticStart >= 0 { - diagnosticEnd = core.FindIndex(savedParseDiagnostics[:diagnosticStart], func(diagnostic *ast.Diagnostic) bool { + diagnosticEnd = core.FindIndex(savedParseDiagnostics[diagnosticStart:], func(diagnostic *ast.Diagnostic) bool { return diagnostic.Pos() >= nextStatement.Pos() }) } else { diff --git a/testdata/baselines/reference/compiler/awaitObjectLiteral.js b/testdata/baselines/reference/compiler/awaitObjectLiteral.js new file mode 100644 index 00000000000..4a995580430 --- /dev/null +++ b/testdata/baselines/reference/compiler/awaitObjectLiteral.js @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/awaitObjectLiteral.ts] //// + +//// [fileA.ts] +export {} +const foo = await { bar: 42 } + +//// [fileB.ts] +export const baz = await { x: 1, y: "hello" } + + +//// [fileA.js] +const foo = await { bar: 42 }; +export {}; +//// [fileB.js] +export const baz = await { x: 1, y: "hello" }; diff --git a/testdata/baselines/reference/compiler/awaitObjectLiteral.symbols b/testdata/baselines/reference/compiler/awaitObjectLiteral.symbols new file mode 100644 index 00000000000..c2e84e4befd --- /dev/null +++ b/testdata/baselines/reference/compiler/awaitObjectLiteral.symbols @@ -0,0 +1,14 @@ +//// [tests/cases/compiler/awaitObjectLiteral.ts] //// + +=== fileA.ts === +export {} +const foo = await { bar: 42 } +>foo : Symbol(foo, Decl(fileA.ts, 1, 5)) +>bar : Symbol(bar, Decl(fileA.ts, 1, 19)) + +=== fileB.ts === +export const baz = await { x: 1, y: "hello" } +>baz : Symbol(baz, Decl(fileB.ts, 0, 12)) +>x : Symbol(x, Decl(fileB.ts, 0, 26)) +>y : Symbol(y, Decl(fileB.ts, 0, 32)) + diff --git a/testdata/baselines/reference/compiler/awaitObjectLiteral.types b/testdata/baselines/reference/compiler/awaitObjectLiteral.types new file mode 100644 index 00000000000..a25e8f32110 --- /dev/null +++ b/testdata/baselines/reference/compiler/awaitObjectLiteral.types @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/awaitObjectLiteral.ts] //// + +=== fileA.ts === +export {} +const foo = await { bar: 42 } +>foo : { bar: number; } +>await { bar: 42 } : { bar: number; } +>{ bar: 42 } : { bar: number; } +>bar : number +>42 : 42 + +=== fileB.ts === +export const baz = await { x: 1, y: "hello" } +>baz : { x: number; y: string; } +>await { x: 1, y: "hello" } : { x: number; y: string; } +>{ x: 1, y: "hello" } : { x: number; y: string; } +>x : number +>1 : 1 +>y : string +>"hello" : "hello" + diff --git a/testdata/baselines/reference/submodule/compiler/reachabilityChecksNoCrash1.errors.txt b/testdata/baselines/reference/submodule/compiler/reachabilityChecksNoCrash1.errors.txt index 721d50fa3a9..fa08b6ff74c 100644 --- a/testdata/baselines/reference/submodule/compiler/reachabilityChecksNoCrash1.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/reachabilityChecksNoCrash1.errors.txt @@ -20,7 +20,6 @@ reachabilityChecksNoCrash1.ts(2,11): error TS2304: Cannot find name 'out'. reachabilityChecksNoCrash1.ts(2,19): error TS1005: ',' expected. reachabilityChecksNoCrash1.ts(3,9): error TS1005: ':' expected. reachabilityChecksNoCrash1.ts(3,16): error TS1109: Expression expected. -reachabilityChecksNoCrash1.ts(3,16): error TS1135: Argument expression expected. reachabilityChecksNoCrash1.ts(3,22): error TS1005: ':' expected. reachabilityChecksNoCrash1.ts(3,22): error TS2304: Cannot find name 'v'. reachabilityChecksNoCrash1.ts(3,24): error TS1005: ',' expected. @@ -34,10 +33,9 @@ reachabilityChecksNoCrash1.ts(4,12): error TS1005: ',' expected. reachabilityChecksNoCrash1.ts(4,24): error TS2304: Cannot find name 'v'. reachabilityChecksNoCrash1.ts(4,26): error TS1005: ',' expected. reachabilityChecksNoCrash1.ts(7,1): error TS1109: Expression expected. -reachabilityChecksNoCrash1.ts(7,1): error TS1128: Declaration or statement expected. -==== reachabilityChecksNoCrash1.ts (37 errors) ==== +==== reachabilityChecksNoCrash1.ts (35 errors) ==== export async function arrayFromAsync(asyncIterable!: AsyncIterable): Promise { ~~~~~~~~~~~~~~ !!! error TS7010: 'arrayFromAsync', which lacks return-type annotation, implicitly has an 'any' return type. @@ -86,8 +84,6 @@ reachabilityChecksNoCrash1.ts(7,1): error TS1128: Declaration or statement expec !!! error TS1005: ':' expected. ~~~~~ !!! error TS1109: Expression expected. - ~~~~~ -!!! error TS1135: Argument expression expected. ~ !!! error TS1005: ':' expected. ~ @@ -121,6 +117,4 @@ reachabilityChecksNoCrash1.ts(7,1): error TS1128: Declaration or statement expec } ~ !!! error TS1109: Expression expected. - ~ -!!! error TS1128: Declaration or statement expected. \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/reachabilityChecksNoCrash1.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/compiler/reachabilityChecksNoCrash1.errors.txt.diff index ff9b9d54b5a..c014d58694e 100644 --- a/testdata/baselines/reference/submoduleAccepted/compiler/reachabilityChecksNoCrash1.errors.txt.diff +++ b/testdata/baselines/reference/submoduleAccepted/compiler/reachabilityChecksNoCrash1.errors.txt.diff @@ -9,38 +9,7 @@ reachabilityChecksNoCrash1.ts(1,84): error TS2304: Cannot find name 'T'. reachabilityChecksNoCrash1.ts(1,86): error TS1011: An element access expression should take an argument. reachabilityChecksNoCrash1.ts(2,11): error TS1005: ':' expected. -@@= skipped -8, +8 lines =@@ - reachabilityChecksNoCrash1.ts(2,19): error TS1005: ',' expected. - reachabilityChecksNoCrash1.ts(3,9): error TS1005: ':' expected. - reachabilityChecksNoCrash1.ts(3,16): error TS1109: Expression expected. -+reachabilityChecksNoCrash1.ts(3,16): error TS1135: Argument expression expected. - reachabilityChecksNoCrash1.ts(3,22): error TS1005: ':' expected. - reachabilityChecksNoCrash1.ts(3,22): error TS2304: Cannot find name 'v'. - reachabilityChecksNoCrash1.ts(3,24): error TS1005: ',' expected. -@@= skipped -13, +14 lines =@@ - reachabilityChecksNoCrash1.ts(4,24): error TS2304: Cannot find name 'v'. - reachabilityChecksNoCrash1.ts(4,26): error TS1005: ',' expected. - reachabilityChecksNoCrash1.ts(7,1): error TS1109: Expression expected. -- -- --==== reachabilityChecksNoCrash1.ts (35 errors) ==== -+reachabilityChecksNoCrash1.ts(7,1): error TS1128: Declaration or statement expected. -+ -+ -+==== reachabilityChecksNoCrash1.ts (37 errors) ==== - export async function arrayFromAsync(asyncIterable!: AsyncIterable): Promise { - ~~~~~~~~~~~~~~ - !!! error TS7010: 'arrayFromAsync', which lacks return-type annotation, implicitly has an 'any' return type. -@@= skipped -51, +52 lines =@@ - !!! error TS1005: ':' expected. - ~~~~~ - !!! error TS1109: Expression expected. -+ ~~~~~ -+!!! error TS1135: Argument expression expected. - ~ - !!! error TS1005: ':' expected. - ~ -@@= skipped -28, +30 lines =@@ +@@= skipped -100, +100 lines =@@ !!! error TS1005: ',' expected. } ~~~~~ @@ -48,8 +17,4 @@ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{ const: never[]; for: any; of: any; asyncIterable: any; out: any; "": any; }'. return out; } - ~ - !!! error TS1109: Expression expected. -+ ~ -+!!! error TS1128: Declaration or statement expected. - \ No newline at end of file + ~ \ No newline at end of file diff --git a/testdata/tests/cases/compiler/awaitObjectLiteral.ts b/testdata/tests/cases/compiler/awaitObjectLiteral.ts index b3413913656..d63cf68d1d2 100644 --- a/testdata/tests/cases/compiler/awaitObjectLiteral.ts +++ b/testdata/tests/cases/compiler/awaitObjectLiteral.ts @@ -4,3 +4,6 @@ // @filename: fileA.ts export {} const foo = await { bar: 42 } + +// @filename: fileB.ts +export const baz = await { x: 1, y: "hello" }