From 5a42af7f6c9ba057171d8a5af6f4b721b8eff10a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 20 Oct 2025 10:25:23 -0700 Subject: [PATCH] go/types, types2: in resolveUnderlying, only compute path when needed When following a RHS chain, the (TypeName) Object path is only needed when there is a cycle (i.e., an error), in which case we can be slow. Rather than always compute the path, only compute it in the error case. In the same vain, allocate the seen map lazily, only when needed. This code could use a test (it doesn't seem to be encountered by our test suite), but I haven't found a case to provoke the error yet. Change-Id: Iff6313394442a251adc56580f746928ec13450fd Reviewed-on: https://go-review.googlesource.com/c/go/+/712321 Auto-Submit: Robert Griesemer LUCI-TryBot-Result: Go LUCI Reviewed-by: Mark Freeman Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/named.go | 16 +++++++++++----- src/go/types/named.go | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 856f33028a..99e2743484 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -593,9 +593,7 @@ func (n *Named) resolveUnderlying() { return } - seen := make(map[*Named]int) - var path []Object - + var seen map[*Named]int // allocated lazily var u Type for rhs := Type(n); u == nil; { switch t := rhs.(type) { @@ -607,9 +605,15 @@ func (n *Named) resolveUnderlying() { case *Named: if i, ok := seen[t]; ok { + // compute cycle path + path := make([]Object, len(seen)) + for t, j := range seen { + path[j] = t.obj + } + path = path[i:] // Note: This code may only be called during type checking, // hence n.check != nil. - n.check.cycleError(path[i:], firstInSrc(path[i:])) + n.check.cycleError(path, firstInSrc(path)) u = Typ[Invalid] break } @@ -625,8 +629,10 @@ func (n *Named) resolveUnderlying() { break } + if seen == nil { + seen = make(map[*Named]int) + } seen[t] = len(seen) - path = append(path, t.obj) assert(t.fromRHS != nil || t.allowNilRHS) rhs = t.fromRHS diff --git a/src/go/types/named.go b/src/go/types/named.go index 5c5c837987..b436d073e6 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -596,9 +596,7 @@ func (n *Named) resolveUnderlying() { return } - seen := make(map[*Named]int) - var path []Object - + var seen map[*Named]int // allocated lazily var u Type for rhs := Type(n); u == nil; { switch t := rhs.(type) { @@ -610,9 +608,15 @@ func (n *Named) resolveUnderlying() { case *Named: if i, ok := seen[t]; ok { + // compute cycle path + path := make([]Object, len(seen)) + for t, j := range seen { + path[j] = t.obj + } + path = path[i:] // Note: This code may only be called during type checking, // hence n.check != nil. - n.check.cycleError(path[i:], firstInSrc(path[i:])) + n.check.cycleError(path, firstInSrc(path)) u = Typ[Invalid] break } @@ -628,8 +632,10 @@ func (n *Named) resolveUnderlying() { break } + if seen == nil { + seen = make(map[*Named]int) + } seen[t] = len(seen) - path = append(path, t.obj) assert(t.fromRHS != nil || t.allowNilRHS) rhs = t.fromRHS -- 2.52.0