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 <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2025-10-20 10:25:23 -07:00 committed by Gopher Robot
parent 4bdb55b5b8
commit 5a42af7f6c
2 changed files with 22 additions and 10 deletions

View file

@ -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

View file

@ -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