1
0
mirror of https://github.com/golang/go synced 2024-11-15 12:10:22 -07:00

go/types, types2: optimize Named type method lookup

Because methods associated with named types are in the
same package as the type, when looking up a method we
don't need to check the package repeatedly.

Rename the global lookupMethod function to methodIndex,
to match the corresponding fieldIndex function (cleanup).

Implement Named.methodIndex, optimized for method lookup
on named types (optimization).

Adjust call sites.

Change-Id: Ifa05306126773262b1af3ce73365b5742b470eb6
Reviewed-on: https://go-review.googlesource.com/c/go/+/562297
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2024-02-06 21:57:06 -08:00 committed by Robert Griesemer
parent f81e498673
commit 7020beeffd
6 changed files with 80 additions and 26 deletions

View File

@ -590,9 +590,9 @@ func fieldIndex(fields []*Var, pkg *Package, name string, foldCase bool) int {
return -1
}
// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
// methodIndex returns the index of and method with matching package and name, or (-1, nil).
// See Object.sameId for the meaning of foldCase.
func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
func methodIndex(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
if m.sameId(pkg, name, foldCase) {

View File

@ -6,6 +6,7 @@ package types2
import (
"cmd/compile/internal/syntax"
"strings"
"sync"
"sync/atomic"
)
@ -444,15 +445,40 @@ func (t *Named) SetUnderlying(underlying Type) {
}
// AddMethod adds method m unless it is already in the method list.
// t must not have type arguments.
// The method must be in the same package as t, and t must not have
// type arguments.
func (t *Named) AddMethod(m *Func) {
assert(samePkg(t.obj.pkg, m.pkg))
assert(t.inst == nil)
t.resolve()
if i, _ := lookupMethod(t.methods, m.pkg, m.name, false); i < 0 {
if t.methodIndex(m.name, false) < 0 {
t.methods = append(t.methods, m)
}
}
// methodIndex returns the index of the method with the given name.
// If foldCase is set, capitalization in the name is ignored.
// The result is negative if no such method exists.
func (t *Named) methodIndex(name string, foldCase bool) int {
if name == "_" {
return -1
}
if foldCase {
for i, m := range t.methods {
if strings.EqualFold(m.name, name) {
return i
}
}
} else {
for i, m := range t.methods {
if m.name == name {
return i
}
}
}
return -1
}
// TODO(gri) Investigate if Unalias can be moved to where underlying is set.
func (t *Named) Underlying() Type { return Unalias(t.resolve().underlying) }
func (t *Named) String() string { return TypeString(t, nil) }
@ -553,15 +579,16 @@ loop:
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
n.resolve()
// If n is an instance, we may not have yet instantiated all of its methods.
// Look up the method index in orig, and only instantiate method at the
// matching index (if any).
i, _ := lookupMethod(n.Origin().methods, pkg, name, foldCase)
if i < 0 {
return -1, nil
if samePkg(n.obj.pkg, pkg) || isExported(name) || foldCase {
// If n is an instance, we may not have yet instantiated all of its methods.
// Look up the method index in orig, and only instantiate method at the
// matching index (if any).
if i := n.Origin().methodIndex(name, foldCase); i >= 0 {
// For instances, m.Method(i) will be different from the orig method.
return i, n.Method(i)
}
}
// For instances, m.Method(i) will be different from the orig method.
return i, n.Method(i)
return -1, nil
}
// context returns the type-checker context.

View File

@ -57,7 +57,7 @@ func (s *_TypeSet) Method(i int) *Func { return s.methods[i] }
// LookupMethod returns the index of and method with matching package and name, or (-1, nil).
func (s *_TypeSet) LookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
return lookupMethod(s.methods, pkg, name, foldCase)
return methodIndex(s.methods, pkg, name, foldCase)
}
func (s *_TypeSet) String() string {

View File

@ -592,9 +592,9 @@ func fieldIndex(fields []*Var, pkg *Package, name string, foldCase bool) int {
return -1
}
// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
// methodIndex returns the index of and method with matching package and name, or (-1, nil).
// See Object.sameId for the meaning of foldCase.
func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
func methodIndex(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
if m.sameId(pkg, name, foldCase) {

View File

@ -8,6 +8,7 @@ package types
import (
"go/token"
"strings"
"sync"
"sync/atomic"
)
@ -446,15 +447,40 @@ func (t *Named) SetUnderlying(underlying Type) {
}
// AddMethod adds method m unless it is already in the method list.
// t must not have type arguments.
// The method must be in the same package as t, and t must not have
// type arguments.
func (t *Named) AddMethod(m *Func) {
assert(samePkg(t.obj.pkg, m.pkg))
assert(t.inst == nil)
t.resolve()
if i, _ := lookupMethod(t.methods, m.pkg, m.name, false); i < 0 {
if t.methodIndex(m.name, false) < 0 {
t.methods = append(t.methods, m)
}
}
// methodIndex returns the index of the method with the given name.
// If foldCase is set, capitalization in the name is ignored.
// The result is negative if no such method exists.
func (t *Named) methodIndex(name string, foldCase bool) int {
if name == "_" {
return -1
}
if foldCase {
for i, m := range t.methods {
if strings.EqualFold(m.name, name) {
return i
}
}
} else {
for i, m := range t.methods {
if m.name == name {
return i
}
}
}
return -1
}
// TODO(gri) Investigate if Unalias can be moved to where underlying is set.
func (t *Named) Underlying() Type { return Unalias(t.resolve().underlying) }
func (t *Named) String() string { return TypeString(t, nil) }
@ -555,15 +581,16 @@ loop:
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
n.resolve()
// If n is an instance, we may not have yet instantiated all of its methods.
// Look up the method index in orig, and only instantiate method at the
// matching index (if any).
i, _ := lookupMethod(n.Origin().methods, pkg, name, foldCase)
if i < 0 {
return -1, nil
if samePkg(n.obj.pkg, pkg) || isExported(name) || foldCase {
// If n is an instance, we may not have yet instantiated all of its methods.
// Look up the method index in orig, and only instantiate method at the
// matching index (if any).
if i := n.Origin().methodIndex(name, foldCase); i >= 0 {
// For instances, m.Method(i) will be different from the orig method.
return i, n.Method(i)
}
}
// For instances, m.Method(i) will be different from the orig method.
return i, n.Method(i)
return -1, nil
}
// context returns the type-checker context.

View File

@ -57,7 +57,7 @@ func (s *_TypeSet) Method(i int) *Func { return s.methods[i] }
// LookupMethod returns the index of and method with matching package and name, or (-1, nil).
func (s *_TypeSet) LookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
return lookupMethod(s.methods, pkg, name, foldCase)
return methodIndex(s.methods, pkg, name, foldCase)
}
func (s *_TypeSet) String() string {