From cdb3763f8e6c966f695ec86eb2fac2f024fa2c08 Mon Sep 17 00:00:00 2001 From: John Favret <64748847+johnfav03@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:37:36 -0700 Subject: [PATCH] added recursion guard for getexplicittypeofsymbol --- internal/checker/checker.go | 1 + internal/checker/flow.go | 4 ++++ .../forOfSelfReferentialDottedName.errors.txt | 17 +++++++++++++++++ .../forOfSelfReferentialDottedName.js | 19 +++++++++++++++++++ .../forOfSelfReferentialDottedName.symbols | 16 ++++++++++++++++ .../forOfSelfReferentialDottedName.types | 17 +++++++++++++++++ .../forOfSelfReferentialDottedName.ts | 6 ++++++ 7 files changed, 80 insertions(+) create mode 100644 testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.errors.txt create mode 100644 testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.js create mode 100644 testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.symbols create mode 100644 testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.types create mode 100644 testdata/tests/cases/compiler/forOfSelfReferentialDottedName.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index b639d488e44..f6066b1a6f3 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -642,6 +642,7 @@ type Checker struct { reverseHomomorphicMappedCache map[ReverseMappedTypeKey]*Type iterationTypesCache map[IterationTypesKey]IterationTypes markerTypes collections.Set[*Type] + resolvingExplicitTypeOfSymbol collections.Set[*ast.Symbol] undefinedSymbol *ast.Symbol argumentsSymbol *ast.Symbol requireSymbol *ast.Symbol diff --git a/internal/checker/flow.go b/internal/checker/flow.go index b60d9c97075..2aa2019ce77 100644 --- a/internal/checker/flow.go +++ b/internal/checker/flow.go @@ -2133,6 +2133,10 @@ func (c *Checker) getTypeOfDottedName(node *ast.Node, diagnostic *ast.Diagnostic func (c *Checker) getExplicitTypeOfSymbol(symbol *ast.Symbol, diagnostic *ast.Diagnostic) *Type { symbol = c.resolveSymbol(symbol) + if !c.resolvingExplicitTypeOfSymbol.AddIfAbsent(symbol) { + return nil + } + defer c.resolvingExplicitTypeOfSymbol.Delete(symbol) if symbol.Flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsMethod|ast.SymbolFlagsClass|ast.SymbolFlagsValueModule) != 0 { return c.getTypeOfSymbol(symbol) } diff --git a/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.errors.txt b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.errors.txt new file mode 100644 index 00000000000..877e1001240 --- /dev/null +++ b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.errors.txt @@ -0,0 +1,17 @@ +forOfSelfReferentialDottedName.ts(3,12): error TS7022: 'a' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +forOfSelfReferentialDottedName.ts(3,17): error TS2448: Block-scoped variable 'a' used before its declaration. + + +==== forOfSelfReferentialDottedName.ts (2 errors) ==== + // A self-referential for-of iterable (`for (const a of a)`) plus a call and a + // later narrowing reference must not infinitely recurse in getExplicitTypeOfSymbol. + for (const a of a) { + ~ +!!! error TS7022: 'a' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. + ~ +!!! error TS2448: Block-scoped variable 'a' used before its declaration. +!!! related TS2728 forOfSelfReferentialDottedName.ts:3:12: 'a' is declared here. + a(); + a; + } + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.js b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.js new file mode 100644 index 00000000000..2c42b7ac8d5 --- /dev/null +++ b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.js @@ -0,0 +1,19 @@ +//// [tests/cases/compiler/forOfSelfReferentialDottedName.ts] //// + +//// [forOfSelfReferentialDottedName.ts] +// A self-referential for-of iterable (`for (const a of a)`) plus a call and a +// later narrowing reference must not infinitely recurse in getExplicitTypeOfSymbol. +for (const a of a) { + a(); + a; +} + + +//// [forOfSelfReferentialDottedName.js] +"use strict"; +// A self-referential for-of iterable (`for (const a of a)`) plus a call and a +// later narrowing reference must not infinitely recurse in getExplicitTypeOfSymbol. +for (const a of a) { + a(); + a; +} diff --git a/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.symbols b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.symbols new file mode 100644 index 00000000000..458bb2b8159 --- /dev/null +++ b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.symbols @@ -0,0 +1,16 @@ +//// [tests/cases/compiler/forOfSelfReferentialDottedName.ts] //// + +=== forOfSelfReferentialDottedName.ts === +// A self-referential for-of iterable (`for (const a of a)`) plus a call and a +// later narrowing reference must not infinitely recurse in getExplicitTypeOfSymbol. +for (const a of a) { +>a : Symbol(a, Decl(forOfSelfReferentialDottedName.ts, 2, 10)) +>a : Symbol(a, Decl(forOfSelfReferentialDottedName.ts, 2, 10)) + + a(); +>a : Symbol(a, Decl(forOfSelfReferentialDottedName.ts, 2, 10)) + + a; +>a : Symbol(a, Decl(forOfSelfReferentialDottedName.ts, 2, 10)) +} + diff --git a/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.types b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.types new file mode 100644 index 00000000000..d30d071f4fd --- /dev/null +++ b/testdata/baselines/reference/compiler/forOfSelfReferentialDottedName.types @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/forOfSelfReferentialDottedName.ts] //// + +=== forOfSelfReferentialDottedName.ts === +// A self-referential for-of iterable (`for (const a of a)`) plus a call and a +// later narrowing reference must not infinitely recurse in getExplicitTypeOfSymbol. +for (const a of a) { +>a : any +>a : any + + a(); +>a() : any +>a : any + + a; +>a : any +} + diff --git a/testdata/tests/cases/compiler/forOfSelfReferentialDottedName.ts b/testdata/tests/cases/compiler/forOfSelfReferentialDottedName.ts new file mode 100644 index 00000000000..3e85f1c0654 --- /dev/null +++ b/testdata/tests/cases/compiler/forOfSelfReferentialDottedName.ts @@ -0,0 +1,6 @@ +// A self-referential for-of iterable (`for (const a of a)`) plus a call and a +// later narrowing reference must not infinitely recurse in getExplicitTypeOfSymbol. +for (const a of a) { + a(); + a; +}