From: Robert Griesemer Date: Mon, 20 Oct 2025 17:25:23 +0000 (-0700) Subject: go/types, types2: in resolveUnderlying, only compute path when needed X-Git-Tag: go1.26rc1~536 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5a42af7f6c9ba057171d8a5af6f4b721b8eff10a;p=gostls13.git 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 --- 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