// not have found it for T (see also issue 8590).
if t := asNamed(T); t != nil {
if p, _ := safeUnderlying(t).(*Pointer); p != nil {
- obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
+ obj, index, indirect = lookupFieldOrMethod(p, false, false, pkg, name)
if _, ok := obj.(*Func); ok {
return nil, nil, false
}
}
}
- return lookupFieldOrMethod(T, addressable, pkg, name)
+ return lookupFieldOrMethod(T, addressable, false, pkg, name)
}
// TODO(gri) The named type consolidation and seen maps below must be
// indirectly via different packages.)
// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod.
-func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+// If checkFold 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).
+func lookupFieldOrMethod(T Type, addressable, checkFold bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
if name == "_" {
seen[named] = true
// look for a matching attached method
- if i, m := lookupMethod(named.methods, pkg, name); m != nil {
+ if i, m := lookupMethodFold(named.methods, pkg, name, checkFold); m != nil {
// potential match
// caution: method may not have a proper signature yet
index = concat(e.index, i)
case *Interface:
// look for a matching method
- if i, m := t.typeSet().LookupMethod(pkg, name); m != nil {
+ if i, m := lookupMethodFold(t.typeSet().methods, pkg, name, checkFold); m != nil {
assert(m.typ != nil)
index = concat(e.index, i)
if obj != nil || e.multiples {
}
case *TypeParam:
- if i, m := t.iface().typeSet().LookupMethod(pkg, name); m != nil {
+ if i, m := lookupMethodFold(t.iface().typeSet().methods, pkg, name, checkFold); m != nil {
assert(m.typ != nil)
index = concat(e.index, i)
if obj != nil || e.multiples {
if !static {
continue
}
+ // We don't do any case-fold check if V is an interface.
return m, f
}
// 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)
+ // TODO(gri) should this be calling LookupFieldOrMethod instead (and why not)?
+ obj, _, _ := lookupFieldOrMethod(V, false, false, m.pkg, m.name)
// 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, false, m.pkg, m.name)
+ if obj != nil {
+ return m, obj.(*Func)
+ }
+ // 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)
if obj != nil {
return m, obj.(*Func)
}
// where m is missing from V, but required by T. It puts the reason in parentheses,
// and may include more have/want info after that. If non-nil, wrongType is a relevant
// method that matches in some way. It may have the correct name, but wrong type, or
-// it may have a pointer receiver.
+// it may have a pointer receiver, or it may have the correct name except wrong case.
func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string {
var r string
var mname string
}
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) {
+ return i, m
+ }
+ }
+ }
+ return -1, nil
+}