mirror of
https://github.com/golang/go
synced 2024-11-14 09:00:21 -07:00
[dev.typeparams] go/types: import lookup logic from dev.go2go
Changes from dev.go2go: + Remove support for pointer designation. + Remove support for method type parameters in missingMethod. We could leave this logic in, but it looked sufficiently shaky that I'd rather not bring in the additional complexity. + Remove the strictness flag parameter to assertableTo, since it isn't used. Change-Id: I812b8d1c49f3b714b166f061fbb7f2e683a0ce86 Reviewed-on: https://go-review.googlesource.com/c/go/+/278333 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Robert Findley <rfindley@google.com> Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
1306435103
commit
a4d4c10340
@ -55,7 +55,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
|
||||
// Thus, if we have a named pointer type, proceed with the underlying
|
||||
// pointer type but discard the result if it is a method since we would
|
||||
// not have found it for T (see also issue 8590).
|
||||
if t, _ := T.(*Named); t != nil {
|
||||
if t := asNamed(T); t != nil {
|
||||
if p, _ := t.underlying.(*Pointer); p != nil {
|
||||
obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name)
|
||||
if _, ok := obj.(*Func); ok {
|
||||
@ -85,7 +85,8 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||
typ, isPtr := deref(T)
|
||||
|
||||
// *typ where typ is an interface has no methods.
|
||||
if isPtr && IsInterface(typ) {
|
||||
// Be cautious: typ may be nil (issue 39634, crash #3).
|
||||
if typ == nil || isPtr && IsInterface(typ) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -106,12 +107,13 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||
var next []embeddedType // embedded types found at current depth
|
||||
|
||||
// look for (pkg, name) in all types at current depth
|
||||
var tpar *TypeParam // set if obj receiver is a type parameter
|
||||
for _, e := range current {
|
||||
typ := e.typ
|
||||
|
||||
// If we have a named type, we may have associated methods.
|
||||
// Look for those first.
|
||||
if named, _ := typ.(*Named); named != nil {
|
||||
if named := asNamed(typ); named != nil {
|
||||
if seen[named] {
|
||||
// We have seen this type before, at a more shallow depth
|
||||
// (note that multiples of this type at the current depth
|
||||
@ -138,10 +140,15 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||
continue // we can't have a matching field or interface method
|
||||
}
|
||||
|
||||
// continue with underlying type
|
||||
typ = named.underlying
|
||||
// continue with underlying type, but only if it's not a type parameter
|
||||
// TODO(gri) is this what we want to do for type parameters? (spec question)
|
||||
typ = named.under()
|
||||
if asTypeParam(typ) != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
tpar = nil
|
||||
switch t := typ.(type) {
|
||||
case *Struct:
|
||||
// look for a matching field and collect embedded types
|
||||
@ -187,6 +194,20 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||
obj = m
|
||||
indirect = e.indirect
|
||||
}
|
||||
|
||||
case *TypeParam:
|
||||
// only consider explicit methods in the type parameter bound, not
|
||||
// methods that may be common to all types in the type list.
|
||||
if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil {
|
||||
assert(m.typ != nil)
|
||||
index = concat(e.index, i)
|
||||
if obj != nil || e.multiples {
|
||||
return nil, index, false // collision
|
||||
}
|
||||
tpar = t
|
||||
obj = m
|
||||
indirect = e.indirect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,8 +217,12 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||
// contains m and the argument list can be assigned to the parameter
|
||||
// list of m. If x is addressable and &x's method set contains m, x.m()
|
||||
// is shorthand for (&x).m()".
|
||||
if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable {
|
||||
return nil, nil, true // pointer/addressable receiver required
|
||||
if f, _ := obj.(*Func); f != nil {
|
||||
// determine if method has a pointer receiver
|
||||
hasPtrRecv := tpar == nil && ptrRecv(f)
|
||||
if hasPtrRecv && !indirect && !addressable {
|
||||
return nil, nil, true // pointer/addressable receiver required
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -269,7 +294,8 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
|
||||
return m, typ != nil
|
||||
}
|
||||
|
||||
// missingMethod is like MissingMethod but accepts a receiver.
|
||||
// missingMethod is like MissingMethod but accepts a *Checker as
|
||||
// receiver and an addressable flag.
|
||||
// The receiver may be nil if missingMethod is invoked through
|
||||
// an exported API call (such as MissingMethod), i.e., when all
|
||||
// methods have been type-checked.
|
||||
@ -285,25 +311,37 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||
return
|
||||
}
|
||||
|
||||
if ityp, _ := V.Underlying().(*Interface); ityp != nil {
|
||||
if ityp := asInterface(V); ityp != nil {
|
||||
check.completeInterface(token.NoPos, ityp)
|
||||
// TODO(gri) allMethods is sorted - can do this more efficiently
|
||||
for _, m := range T.allMethods {
|
||||
_, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
|
||||
switch {
|
||||
case obj == nil:
|
||||
if static {
|
||||
return m, nil
|
||||
_, f := lookupMethod(ityp.allMethods, m.pkg, m.name)
|
||||
|
||||
if f == nil {
|
||||
// if m is the magic method == we're ok (interfaces are comparable)
|
||||
if m.name == "==" || !static {
|
||||
continue
|
||||
}
|
||||
case !check.identical(obj.Type(), m.typ):
|
||||
return m, obj
|
||||
return m, f
|
||||
}
|
||||
|
||||
if !check.identical(f.Type(), m.Type()) {
|
||||
return m, f
|
||||
}
|
||||
|
||||
// TODO(rFindley) delete this note once the spec has stabilized to
|
||||
// exclude method type parameters.
|
||||
// NOTE: if enabling method type parameters, we need to unify f.Type()
|
||||
// and m.Type() here to verify that their type parameters align (assuming
|
||||
// this behaves correctly with respect to type bounds).
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// A concrete type implements T if it implements all methods of T.
|
||||
for _, m := range T.allMethods {
|
||||
// TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
|
||||
obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name)
|
||||
|
||||
// Check if *V implements this method of T.
|
||||
@ -318,6 +356,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||
// we must have a method (not a field of matching function type)
|
||||
f, _ := obj.(*Func)
|
||||
if f == nil {
|
||||
// if m is the magic method == and V is comparable, we're ok
|
||||
if m.name == "==" && Comparable(V) {
|
||||
continue
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@ -326,9 +368,16 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||
check.objDecl(f, nil)
|
||||
}
|
||||
|
||||
if !check.identical(f.typ, m.typ) {
|
||||
if !check.identical(f.Type(), m.Type()) {
|
||||
return m, f
|
||||
}
|
||||
|
||||
// TODO(rFindley) delete this note once the spec has stabilized to exclude
|
||||
// method type parameters.
|
||||
// NOTE: if enabling method type parameters, one needs to subst any
|
||||
// receiver type parameters for V here, and unify f.Type() with m.Type() to
|
||||
// verify that their type parameters align (assuming this behaves correctly
|
||||
// with respect to type bounds).
|
||||
}
|
||||
|
||||
return
|
||||
@ -339,11 +388,13 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||
// method required by V and whether it is missing or just has the wrong type.
|
||||
// The receiver may be nil if assertableTo is invoked through an exported API call
|
||||
// (such as AssertableTo), i.e., when all methods have been type-checked.
|
||||
// If the global constant forceStrict is set, assertions that are known to fail
|
||||
// are not permitted.
|
||||
func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) {
|
||||
// no static check is required if T is an interface
|
||||
// spec: "If T is an interface type, x.(T) asserts that the
|
||||
// dynamic type of x implements the interface T."
|
||||
if _, ok := T.Underlying().(*Interface); ok && !forceStrict {
|
||||
if asInterface(T) != nil && !forceStrict {
|
||||
return
|
||||
}
|
||||
return check.missingMethod(T, V, false)
|
||||
@ -361,8 +412,8 @@ func deref(typ Type) (Type, bool) {
|
||||
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
|
||||
// (named or unnamed) struct and returns its base. Otherwise it returns typ.
|
||||
func derefStructPtr(typ Type) Type {
|
||||
if p, _ := typ.Underlying().(*Pointer); p != nil {
|
||||
if _, ok := p.base.Underlying().(*Struct); ok {
|
||||
if p := asPointer(typ); p != nil {
|
||||
if asStruct(p.base) != nil {
|
||||
return p.base
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,9 @@ func NewMethodSet(T Type) *MethodSet {
|
||||
// WARNING: The code in this function is extremely subtle - do not modify casually!
|
||||
// This function and lookupFieldOrMethod should be kept in sync.
|
||||
|
||||
// TODO(gri) This code is out-of-sync with the lookup code at this point.
|
||||
// Need to update.
|
||||
|
||||
// method set up to the current depth, allocated lazily
|
||||
var base methodSet
|
||||
|
||||
@ -108,7 +111,7 @@ func NewMethodSet(T Type) *MethodSet {
|
||||
|
||||
// If we have a named type, we may have associated methods.
|
||||
// Look for those first.
|
||||
if named, _ := typ.(*Named); named != nil {
|
||||
if named := asNamed(typ); named != nil {
|
||||
if seen[named] {
|
||||
// We have seen this type before, at a more shallow depth
|
||||
// (note that multiples of this type at the current depth
|
||||
|
Loading…
Reference in New Issue
Block a user