From 22cd50fb741c1a7cec4701e6b8d7f04eac2dbfd8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:26:24 +0000 Subject: [PATCH 1/4] Initial plan From 0e9fa90b3388ee340dc758f79b3a466252f1bf69 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:50:58 +0000 Subject: [PATCH 2/4] Port TypeScript PR #62950: Ignore computed name parents when looking up containing functions Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- internal/ast/utilities.go | 13 ++++++++++++- internal/checker/utilities.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 6338dedc582..427a71d58d8 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -3885,7 +3885,18 @@ func IsExpandoInitializer(initializer *Node) bool { } func GetContainingFunction(node *Node) *Node { - return FindAncestor(node.Parent, IsFunctionLike) + node = node.Parent + for node != nil { + if node.Kind == KindComputedPropertyName { + node = node.Parent.Parent + continue + } + if IsFunctionLike(node) { + return node + } + node = node.Parent + } + return nil } func IsImplicitlyExportedJSTypeAlias(node *Node) bool { diff --git a/internal/checker/utilities.go b/internal/checker/utilities.go index 6fdedd0a912..41e15cd9da3 100644 --- a/internal/checker/utilities.go +++ b/internal/checker/utilities.go @@ -816,7 +816,36 @@ func (s *orderedSet[T]) add(value T) { } func getContainingFunctionOrClassStaticBlock(node *ast.Node) *ast.Node { - return ast.FindAncestor(node.Parent, ast.IsFunctionLikeOrClassStaticBlockDeclaration) + node = node.Parent + for node != nil { + if node.Kind == ast.KindComputedPropertyName { + node = node.Parent.Parent + continue + } + if ast.IsFunctionLikeOrClassStaticBlockDeclaration(node) { + return node + } + node = node.Parent + } + return nil +} + +func getContainingClassStaticBlock(node *ast.Node) *ast.Node { + node = node.Parent + for node != nil { + if node.Kind == ast.KindComputedPropertyName { + node = node.Parent.Parent + continue + } + if ast.IsClassLike(node) || ast.IsFunctionLike(node) { + return nil + } + if ast.IsClassStaticBlockDeclaration(node) { + return node + } + node = node.Parent + } + return nil } func isNodeDescendantOf(node *ast.Node, ancestor *ast.Node) bool { From 18afbacf86f0cef6c78a72f882df5acb89552ede Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:59:47 +0000 Subject: [PATCH 3/4] Add nil checks for Parent pointers in computed property name handling Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- internal/ast/utilities.go | 7 +++++-- internal/checker/utilities.go | 14 ++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 427a71d58d8..a313d72df85 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -3888,8 +3888,11 @@ func GetContainingFunction(node *Node) *Node { node = node.Parent for node != nil { if node.Kind == KindComputedPropertyName { - node = node.Parent.Parent - continue + if node.Parent != nil && node.Parent.Parent != nil { + node = node.Parent.Parent + continue + } + return nil } if IsFunctionLike(node) { return node diff --git a/internal/checker/utilities.go b/internal/checker/utilities.go index 41e15cd9da3..d151e6d0b20 100644 --- a/internal/checker/utilities.go +++ b/internal/checker/utilities.go @@ -819,8 +819,11 @@ func getContainingFunctionOrClassStaticBlock(node *ast.Node) *ast.Node { node = node.Parent for node != nil { if node.Kind == ast.KindComputedPropertyName { - node = node.Parent.Parent - continue + if node.Parent != nil && node.Parent.Parent != nil { + node = node.Parent.Parent + continue + } + return nil } if ast.IsFunctionLikeOrClassStaticBlockDeclaration(node) { return node @@ -834,8 +837,11 @@ func getContainingClassStaticBlock(node *ast.Node) *ast.Node { node = node.Parent for node != nil { if node.Kind == ast.KindComputedPropertyName { - node = node.Parent.Parent - continue + if node.Parent != nil && node.Parent.Parent != nil { + node = node.Parent.Parent + continue + } + return nil } if ast.IsClassLike(node) || ast.IsFunctionLike(node) { return nil From c0af02c6ad3f78497f6bf92b5d530c7a430a6dfd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 21:52:40 +0000 Subject: [PATCH 4/4] Remove unused getContainingClassStaticBlock and add tests from upstream PR Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- internal/checker/utilities.go | 21 ------------ ...ContextuallyTypedObjectNoCrash1.errors.txt | 14 ++++++++ ...eOfContextuallyTypedObjectNoCrash1.symbols | 17 ++++++++++ ...ameOfContextuallyTypedObjectNoCrash1.types | 20 +++++++++++ .../conformance/classStaticBlock29.errors.txt | 20 +++++++++++ .../conformance/classStaticBlock29.symbols | 21 ++++++++++++ .../conformance/classStaticBlock29.types | 33 +++++++++++++++++++ ...edNameOfContextuallyTypedObjectNoCrash1.ts | 11 +++++++ .../classStaticBlock/classStaticBlock29.ts | 11 +++++++ 9 files changed, 147 insertions(+), 21 deletions(-) create mode 100644 testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.errors.txt create mode 100644 testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.symbols create mode 100644 testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.types create mode 100644 testdata/baselines/reference/conformance/classStaticBlock29.errors.txt create mode 100644 testdata/baselines/reference/conformance/classStaticBlock29.symbols create mode 100644 testdata/baselines/reference/conformance/classStaticBlock29.types create mode 100644 testdata/tests/cases/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts create mode 100644 testdata/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts diff --git a/internal/checker/utilities.go b/internal/checker/utilities.go index d151e6d0b20..d58c0b8c492 100644 --- a/internal/checker/utilities.go +++ b/internal/checker/utilities.go @@ -833,27 +833,6 @@ func getContainingFunctionOrClassStaticBlock(node *ast.Node) *ast.Node { return nil } -func getContainingClassStaticBlock(node *ast.Node) *ast.Node { - node = node.Parent - for node != nil { - if node.Kind == ast.KindComputedPropertyName { - if node.Parent != nil && node.Parent.Parent != nil { - node = node.Parent.Parent - continue - } - return nil - } - if ast.IsClassLike(node) || ast.IsFunctionLike(node) { - return nil - } - if ast.IsClassStaticBlockDeclaration(node) { - return node - } - node = node.Parent - } - return nil -} - func isNodeDescendantOf(node *ast.Node, ancestor *ast.Node) bool { for node != nil { if node == ancestor { diff --git a/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.errors.txt b/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.errors.txt new file mode 100644 index 00000000000..46113a10d1d --- /dev/null +++ b/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.errors.txt @@ -0,0 +1,14 @@ +yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts(5,7): error TS7057: 'yield' expression implicitly results in an 'any' type because its containing generator lacks a return-type annotation. + + +==== yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/62941 + + function* g() { + let x: any = { + *[yield 0]() {}, + ~~~~~ +!!! error TS7057: 'yield' expression implicitly results in an 'any' type because its containing generator lacks a return-type annotation. + }; + } + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.symbols b/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.symbols new file mode 100644 index 00000000000..4e406efe098 --- /dev/null +++ b/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.symbols @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts] //// + +=== yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts === +// https://github.com/microsoft/TypeScript/issues/62941 + +function* g() { +>g : Symbol(g, Decl(yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts, 0, 0)) + + let x: any = { +>x : Symbol(x, Decl(yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts, 3, 5)) + + *[yield 0]() {}, +>[yield 0] : Symbol([yield 0], Decl(yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts, 3, 16)) + + }; +} + diff --git a/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.types b/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.types new file mode 100644 index 00000000000..0347c10be22 --- /dev/null +++ b/testdata/baselines/reference/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.types @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts] //// + +=== yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts === +// https://github.com/microsoft/TypeScript/issues/62941 + +function* g() { +>g : () => Generator + + let x: any = { +>x : any +>{ *[yield 0]() {}, } : { [x: number]: () => Generator; } + + *[yield 0]() {}, +>[yield 0] : () => Generator +>yield 0 : any +>0 : 0 + + }; +} + diff --git a/testdata/baselines/reference/conformance/classStaticBlock29.errors.txt b/testdata/baselines/reference/conformance/classStaticBlock29.errors.txt new file mode 100644 index 00000000000..2932f2f593e --- /dev/null +++ b/testdata/baselines/reference/conformance/classStaticBlock29.errors.txt @@ -0,0 +1,20 @@ +classStaticBlock29.ts(3,19): error TS18037: 'await' expression cannot be used inside a class static block. +classStaticBlock29.ts(4,19): error TS18037: 'await' expression cannot be used inside a class static block. +classStaticBlock29.ts(5,23): error TS18037: 'await' expression cannot be used inside a class static block. + + +==== classStaticBlock29.ts (3 errors) ==== + class C { + static { + const o1 = { [await 1]: '' }; + ~~~~~~~ +!!! error TS18037: 'await' expression cannot be used inside a class static block. + const o2 = { [await 1]() { return ''; } }; + ~~~~~~~ +!!! error TS18037: 'await' expression cannot be used inside a class static block. + const o3 = { get [await 1]() { return ''; } }; + ~~~~~~~ +!!! error TS18037: 'await' expression cannot be used inside a class static block. + } + } + \ No newline at end of file diff --git a/testdata/baselines/reference/conformance/classStaticBlock29.symbols b/testdata/baselines/reference/conformance/classStaticBlock29.symbols new file mode 100644 index 00000000000..94892fe8e01 --- /dev/null +++ b/testdata/baselines/reference/conformance/classStaticBlock29.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +class C { +>C : Symbol(C, Decl(classStaticBlock29.ts, 0, 0)) + + static { + const o1 = { [await 1]: '' }; +>o1 : Symbol(o1, Decl(classStaticBlock29.ts, 2, 9)) +>[await 1] : Symbol([await 1], Decl(classStaticBlock29.ts, 2, 16)) + + const o2 = { [await 1]() { return ''; } }; +>o2 : Symbol(o2, Decl(classStaticBlock29.ts, 3, 9)) +>[await 1] : Symbol([await 1], Decl(classStaticBlock29.ts, 3, 16)) + + const o3 = { get [await 1]() { return ''; } }; +>o3 : Symbol(o3, Decl(classStaticBlock29.ts, 4, 9)) +>[await 1] : Symbol([await 1], Decl(classStaticBlock29.ts, 4, 16)) + } +} + diff --git a/testdata/baselines/reference/conformance/classStaticBlock29.types b/testdata/baselines/reference/conformance/classStaticBlock29.types new file mode 100644 index 00000000000..fdcf17f98c2 --- /dev/null +++ b/testdata/baselines/reference/conformance/classStaticBlock29.types @@ -0,0 +1,33 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +class C { +>C : C + + static { + const o1 = { [await 1]: '' }; +>o1 : { 1: string; } +>{ [await 1]: '' } : { 1: string; } +>[await 1] : string +>await 1 : 1 +>1 : 1 +>'' : "" + + const o2 = { [await 1]() { return ''; } }; +>o2 : { 1(): string; } +>{ [await 1]() { return ''; } } : { 1(): string; } +>[await 1] : () => string +>await 1 : 1 +>1 : 1 +>'' : "" + + const o3 = { get [await 1]() { return ''; } }; +>o3 : {} +>{ get [await 1]() { return ''; } } : {} +>[await 1] : string +>await 1 : 1 +>1 : 1 +>'' : "" + } +} + diff --git a/testdata/tests/cases/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts b/testdata/tests/cases/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts new file mode 100644 index 00000000000..081cebcab3d --- /dev/null +++ b/testdata/tests/cases/compiler/yieldInComputedNameOfContextuallyTypedObjectNoCrash1.ts @@ -0,0 +1,11 @@ +// @strict: true +// @target: esnext +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/62941 + +function* g() { + let x: any = { + *[yield 0]() {}, + }; +} diff --git a/testdata/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts b/testdata/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts new file mode 100644 index 00000000000..5a086ffbe53 --- /dev/null +++ b/testdata/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts @@ -0,0 +1,11 @@ +// @strict: true +// @target: esnext +// @noEmit: true + +class C { + static { + const o1 = { [await 1]: '' }; + const o2 = { [await 1]() { return ''; } }; + const o3 = { get [await 1]() { return ''; } }; + } +}