mirror of https://github.com/golang/go.git
go/types: fix lookup of methods of pointers to type parameters
Since the type bound of a type parameter is an interface, no method is found if the receiver is a pointer to a type parameter (pointers to interfaces have no methods). Ignore the indirection in this case. Change-Id: Ie2af78b4cfb2f70b5d4f1d2afc631716a10ff7d9
This commit is contained in:
parent
f81ad49939
commit
62683a7752
|
|
@ -4,6 +4,7 @@ so we have a better track record. I only switched to this file in Nov 2019, henc
|
|||
----------------------------------------------------------------------------------------------------
|
||||
TODO
|
||||
|
||||
- revisit all uses of derefUnpack in lookup.go (see local comments); create test cases
|
||||
- implement type-checking for type parameters with pointer designation in contracts
|
||||
- figure out how to translate methods with pointer designation into interface bounds
|
||||
- review use of Contract.TParams field - it seems like it's only needed for length checks?
|
||||
|
|
|
|||
|
|
@ -82,7 +82,17 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
|||
return // blank fields/methods are never found
|
||||
}
|
||||
|
||||
typ, isPtr := derefUnpack(T)
|
||||
typ, isPtr := deref(T)
|
||||
|
||||
// If we have a type parameter, ignore isPtr otherwise we would
|
||||
// return immediately below since the type parameter bound is an
|
||||
// interface. This is needed for methods on variables that are
|
||||
// pointers to values of type parameter type.
|
||||
// TODO(gri) Should this be done in derefUnpack?
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
typ = tpar.bound
|
||||
isPtr = false
|
||||
}
|
||||
|
||||
// *typ where typ is an interface has no methods.
|
||||
if isPtr && IsInterface(typ) {
|
||||
|
|
@ -166,6 +176,9 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
|||
// this depth, f.typ appears multiple times at the next
|
||||
// depth.
|
||||
if obj == nil && f.embedded {
|
||||
// TODO(gri) investigate derefUnpack here (see
|
||||
// comment in the beginning on unpacking type
|
||||
// parameters).
|
||||
typ, isPtr := derefUnpack(f.typ)
|
||||
// TODO(gri) optimization: ignore types that can't
|
||||
// have fields or methods (only Named, Struct, and
|
||||
|
|
@ -409,8 +422,7 @@ func deref(typ Type) (Type, bool) {
|
|||
return typ, false
|
||||
}
|
||||
|
||||
// derefUnpack is like deref but it also unpacks type parameters
|
||||
// and parameterized types.
|
||||
// derefUnpack is like deref but it also unpacks type parameters.
|
||||
func derefUnpack(typ Type) (Type, bool) {
|
||||
typ, ptr := deref(typ)
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
|
|
|
|||
|
|
@ -47,3 +47,34 @@ func _() {
|
|||
var m map[int]int
|
||||
Equal(m, nil)
|
||||
}
|
||||
|
||||
// If we have a receiver of pointer type (below: *T) we must ignore
|
||||
// the pointer in the implementation of the method lookup because
|
||||
// the type bound of T is an interface an pointer to interface types
|
||||
// have no methods and then the lookup would fail.
|
||||
contract C(T) {
|
||||
T m()
|
||||
}
|
||||
|
||||
// using contract C
|
||||
func _(type T C)(x *T) {
|
||||
x.m()
|
||||
}
|
||||
|
||||
// using an interface as bound
|
||||
func _(type T interface{ m() })(x *T) {
|
||||
x.m()
|
||||
}
|
||||
|
||||
// This is the original (simplified) program causing the same issue.
|
||||
type GraphP(type Node, Edge GP) struct {
|
||||
nodes []*Node
|
||||
}
|
||||
|
||||
contract GP(Node, Edge) {
|
||||
Node Edges() []*Edge
|
||||
}
|
||||
|
||||
func (g *GraphP(Node, Edge)) Edges(n *Node) []*Edge {
|
||||
return n.Edges()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
|
||||
package p
|
||||
|
||||
// TODO(gri) this should work
|
||||
contract C(T) {
|
||||
T m()
|
||||
}
|
||||
|
||||
func _(type T C)(x *T) {
|
||||
x.m /* ERROR no field or method m */ ()
|
||||
x.m()
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue