1
0
mirror of https://github.com/golang/go synced 2024-09-29 04:24:36 -06:00

go/types, types2: use same method lookup code in both type checkers

types2 has some code to handle case-folding when doing method lookups
which was missing in go/types. This change is a first step to match
the implementations. Specifically:

In types2:
- remove the lookupMethodFold names in favor of just lookupMethod,
  but with the foldCase flag (e.g., instead if lookupMethodFold,
  we just use lookupMethod)
- rename checkFold to foldCase everywhere
- add foldCase parameter where it was missing
- moved foldCase paremeter to the end in lookupFieldOrMethod
- no functionality changes

In go/types:
- match function signatures with types2 use
- always provide false as argument for foldCase for now
- no functionality changes

Preparation for fixing some of the outstanding error reporting issues.

Change-Id: If129a5feb89ddf96a3596e8d73b23afa591875a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/382461
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2022-02-02 13:18:56 -08:00
parent 63e833154c
commit d5bd3f9a6c
8 changed files with 47 additions and 62 deletions

View File

@ -55,7 +55,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// not have found it for T (see also issue 8590).
if t, _ := T.(*Named); t != nil {
if p, _ := t.Underlying().(*Pointer); p != nil {
obj, index, indirect = lookupFieldOrMethod(p, false, false, pkg, name)
obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name, false)
if _, ok := obj.(*Func); ok {
return nil, nil, false
}
@ -63,7 +63,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
}
}
obj, index, indirect = lookupFieldOrMethod(T, addressable, false, pkg, name)
obj, index, indirect = lookupFieldOrMethod(T, addressable, pkg, name, false)
// If we didn't find anything and if we have a type parameter with a structural constraint,
// see if there is a matching field (but not a method, those need to be declared explicitly
@ -71,7 +71,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// are ok here because only fields are accepted as results.
if obj == nil && isTypeParam(T) {
if t := structuralType(T); t != nil {
obj, index, indirect = lookupFieldOrMethod(t, addressable, false, pkg, name)
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only
}
@ -86,11 +86,11 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// indirectly via different packages.)
// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod.
// If checkFold is true, the lookup for methods will include looking for any method
// If foldCase is true, the lookup for methods will include looking for any method
// which case-folds to the same as 'name' (used for giving helpful error messages).
//
// The resulting object may not be fully type-checked.
func lookupFieldOrMethod(T Type, addressable, checkFold bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
if name == "_" {
@ -144,7 +144,7 @@ func lookupFieldOrMethod(T Type, addressable, checkFold bool, pkg *Package, name
// look for a matching attached method
named.resolve(nil)
if i, m := named.lookupMethodFold(pkg, name, checkFold); m != nil {
if i, m := named.lookupMethod(pkg, name, foldCase); m != nil {
// potential match
// caution: method may not have a proper signature yet
index = concat(e.index, i)
@ -191,7 +191,7 @@ func lookupFieldOrMethod(T Type, addressable, checkFold bool, pkg *Package, name
case *Interface:
// look for a matching method (interface may be a type parameter)
if i, m := lookupMethodFold(t.typeSet().methods, pkg, name, checkFold); m != nil {
if i, m := t.typeSet().LookupMethod(pkg, name, foldCase); m != nil {
assert(m.typ != nil)
index = concat(e.index, i)
if obj != nil || e.multiples {
@ -308,7 +308,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
if ityp, _ := under(V).(*Interface); ityp != nil {
// TODO(gri) the methods are sorted - could do this more efficiently
for _, m := range T.typeSet().methods {
_, f := ityp.typeSet().LookupMethod(m.pkg, m.name)
_, f := ityp.typeSet().LookupMethod(m.pkg, m.name, false)
if f == nil {
if !static {
@ -339,17 +339,17 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// A concrete type implements T if it implements all methods of T.
for _, m := range T.typeSet().methods {
// TODO(gri) should this be calling LookupFieldOrMethod instead (and why not)?
obj, _, _ := lookupFieldOrMethod(V, false, false, m.pkg, m.name)
obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name, false)
// Check if *V implements this method of T.
if obj == nil {
ptr := NewPointer(V)
obj, _, _ = lookupFieldOrMethod(ptr, false, false, m.pkg, m.name)
obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name, false)
if obj == nil {
// If we didn't find the exact method (even with pointer
// receiver), look to see if there is a method that
// matches m.name with case-folding.
obj, _, _ = lookupFieldOrMethod(V, false, true, m.pkg, m.name)
obj, _, _ = lookupFieldOrMethod(V, false, m.pkg, m.name, true)
}
if obj != nil {
// methods may not have a fully set up signature yet
@ -513,28 +513,11 @@ func fieldIndex(fields []*Var, pkg *Package, name string) int {
}
// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
// If foldCase is true, method names are considered equal if they are equal with case folding.
func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
if m.sameId(pkg, name) {
return i, m
}
}
}
return -1, nil
}
// lookupMethodFold is like lookupMethod, but if checkFold is true, it matches a method
// name if the names are equal with case folding.
func lookupMethodFold(methods []*Func, pkg *Package, name string, checkFold bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
if m.name != name && !(checkFold && strings.EqualFold(m.name, name)) {
continue
}
// Use m.name, since we've already checked that m.name and
// name are equal with folding.
if m.sameId(pkg, m.name) {
if (m.name == name || foldCase && strings.EqualFold(m.name, name)) && m.sameId(pkg, m.name) {
return i, m
}
}

View File

@ -41,20 +41,20 @@ func (l *methodList) isLazy() bool {
// panics if the receiver is lazy.
func (l *methodList) Add(m *Func) {
assert(!l.isLazy())
if i, _ := lookupMethod(l.methods, m.pkg, m.name); i < 0 {
if i, _ := lookupMethod(l.methods, m.pkg, m.name, false); i < 0 {
l.methods = append(l.methods, m)
}
}
// LookupFold looks up the method identified by pkg and name in the receiver.
// LookupFold panics if the receiver is lazy. If checkFold is true, it matches
// a method name if the names are equal with case folding.
func (l *methodList) LookupFold(pkg *Package, name string, checkFold bool) (int, *Func) {
// Lookup looks up the method identified by pkg and name in the receiver.
// Lookup panics if the receiver is lazy. If foldCase is true, method names
// are considered equal if they are equal with case folding.
func (l *methodList) Lookup(pkg *Package, name string, foldCase bool) (int, *Func) {
assert(!l.isLazy())
if l == nil {
return -1, nil
}
return lookupMethodFold(l.methods, pkg, name, checkFold)
return lookupMethod(l.methods, pkg, name, foldCase)
}
// Len returns the length of the method list.

View File

@ -297,12 +297,12 @@ func (n *Named) setUnderlying(typ Type) {
}
}
func (n *Named) lookupMethodFold(pkg *Package, name string, checkFold bool) (int, *Func) {
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
n.resolve(nil)
// 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, _ := n.orig.methods.LookupFold(pkg, name, checkFold)
i, _ := n.orig.methods.Lookup(pkg, name, foldCase)
if i < 0 {
return -1, nil
}

View File

@ -58,9 +58,8 @@ func (s *_TypeSet) NumMethods() int { return len(s.methods) }
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) (int, *Func) {
// TODO(gri) s.methods is sorted - consider binary search
return lookupMethod(s.methods, pkg, name)
func (s *_TypeSet) LookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
return lookupMethod(s.methods, pkg, name, foldCase)
}
func (s *_TypeSet) String() string {

View File

@ -55,7 +55,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// not have found it for T (see also issue 8590).
if t, _ := T.(*Named); t != nil {
if p, _ := t.Underlying().(*Pointer); p != nil {
obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name, false)
if _, ok := obj.(*Func); ok {
return nil, nil, false
}
@ -63,7 +63,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
}
}
obj, index, indirect = lookupFieldOrMethod(T, addressable, pkg, name)
obj, index, indirect = lookupFieldOrMethod(T, addressable, pkg, name, false)
// If we didn't find anything and if we have a type parameter with a structural constraint,
// see if there is a matching field (but not a method, those need to be declared explicitly
@ -71,7 +71,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// are ok here because only fields are accepted as results.
if obj == nil && isTypeParam(T) {
if t := structuralType(T); t != nil {
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name)
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only
}
@ -86,9 +86,11 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// indirectly via different packages.)
// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod.
// If foldCase is true, the lookup for methods will include looking for any method
// which case-folds to the same as 'name' (used for giving helpful error messages).
//
// The resulting object may not be fully type-checked.
func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
if name == "_" {
@ -142,7 +144,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// look for a matching attached method
named.resolve(nil)
if i, m := named.lookupMethod(pkg, name); m != nil {
if i, m := named.lookupMethod(pkg, name, foldCase); m != nil {
// potential match
// caution: method may not have a proper signature yet
index = concat(e.index, i)
@ -189,7 +191,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
case *Interface:
// look for a matching method (interface may be a type parameter)
if i, m := t.typeSet().LookupMethod(pkg, name); m != nil {
if i, m := t.typeSet().LookupMethod(pkg, name, foldCase); m != nil {
assert(m.typ != nil)
index = concat(e.index, i)
if obj != nil || e.multiples {
@ -301,7 +303,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
if ityp, _ := under(V).(*Interface); ityp != nil {
// TODO(gri) the methods are sorted - could do this more efficiently
for _, m := range T.typeSet().methods {
_, f := ityp.typeSet().LookupMethod(m.pkg, m.name)
_, f := ityp.typeSet().LookupMethod(m.pkg, m.name, false)
if f == nil {
if !static {
@ -331,12 +333,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// A concrete type implements T if it implements all methods of T.
for _, m := range T.typeSet().methods {
// TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name, false)
// Check if *V implements this method of T.
if obj == nil {
ptr := NewPointer(V)
obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name)
obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name, false)
if obj != nil {
// methods may not have a fully set up signature yet
@ -502,10 +504,11 @@ func fieldIndex(fields []*Var, pkg *Package, name string) int {
}
// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
// If foldCase is true, method names are considered equal if they are equal with case folding.
func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
if m.sameId(pkg, name) {
if (m.name == name || foldCase && strings.EqualFold(m.name, name)) && m.sameId(pkg, m.name) {
return i, m
}
}

View File

@ -41,19 +41,20 @@ func (l *methodList) isLazy() bool {
// panics if the receiver is lazy.
func (l *methodList) Add(m *Func) {
assert(!l.isLazy())
if i, _ := lookupMethod(l.methods, m.pkg, m.name); i < 0 {
if i, _ := lookupMethod(l.methods, m.pkg, m.name, false); i < 0 {
l.methods = append(l.methods, m)
}
}
// Lookup looks up the method identified by pkg and name in the receiver.
// Lookup panics if the receiver is lazy.
func (l *methodList) Lookup(pkg *Package, name string) (int, *Func) {
// Lookup panics if the receiver is lazy. If foldCase is true, method names
// are considered equal if they are equal with case folding.
func (l *methodList) Lookup(pkg *Package, name string, foldCase bool) (int, *Func) {
assert(!l.isLazy())
if l == nil {
return -1, nil
}
return lookupMethod(l.methods, pkg, name)
return lookupMethod(l.methods, pkg, name, foldCase)
}
// Len returns the length of the method list.

View File

@ -299,12 +299,12 @@ func (n *Named) setUnderlying(typ Type) {
}
}
func (n *Named) lookupMethod(pkg *Package, name string) (int, *Func) {
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
n.resolve(nil)
// 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, _ := n.orig.methods.Lookup(pkg, name)
i, _ := n.orig.methods.Lookup(pkg, name, foldCase)
if i < 0 {
return -1, nil
}

View File

@ -56,9 +56,8 @@ func (s *_TypeSet) NumMethods() int { return len(s.methods) }
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) (int, *Func) {
// TODO(gri) s.methods is sorted - consider binary search
return lookupMethod(s.methods, pkg, name)
func (s *_TypeSet) LookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
return lookupMethod(s.methods, pkg, name, foldCase)
}
func (s *_TypeSet) String() string {