]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: determine hasPtrRecv property from source rather than type
authorRobert Griesemer <gri@golang.org>
Wed, 3 Oct 2018 21:40:09 +0000 (14:40 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 4 Oct 2018 15:21:01 +0000 (15:21 +0000)
LookupFieldOrMethod needs to know if a method receiver is a pointer
type. Until now this was computed from the the method signature's
receiver, which required the method signature to be type-checked.
Furthermore, it required the receiver to be set before the method
signature was fully type-checked in some cases (see issue #6638).

This CL remembers this property during object resolution, when we
know it from the source.

With this CL, method signatures don't need to be type-checked before
they can be looked up; this is a first step towards separating
type checking of types and type-checking of associated methods.

Updates #23203.
Updates #26854.

Change-Id: Ie3eb7976e8fe8176ea1b284fa7471a4b7000f80b
Reviewed-on: https://go-review.googlesource.com/c/139422
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
src/go/types/methodset.go
src/go/types/object.go
src/go/types/resolver.go
src/go/types/typexpr.go

index 2b810da728340966eebac98f9cb5ab1595a74e17..c25236656e5d7a8153f5521faeea41b6c2078f3a 100644 (file)
@@ -255,8 +255,17 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
 }
 
 // ptrRecv reports whether the receiver is of the form *T.
-// The receiver must exist.
 func ptrRecv(f *Func) bool {
-       _, isPtr := deref(f.typ.(*Signature).recv.typ)
-       return isPtr
+       // If a method's type is set, use that as the source of truth for the receiver.
+       if f.typ != nil {
+               _, isPtr := deref(f.typ.(*Signature).recv.typ)
+               return isPtr
+       }
+
+       // If a method's type is not set it may be a method/function that is:
+       // 1) client-supplied (via NewFunc with no signature), or
+       // 2) internally created but not yet type-checked.
+       // For case 1) we can't do anything; the client must know what they are doing.
+       // For case 2) we can use the information gathered by the resolver.
+       return f.hasPtrRecv
 }
index 07adfbc34c3900dc1820429c1e3b84f3d9e9c38b..cf773238a0df6e023c0d1933763737597b854ec4 100644 (file)
@@ -294,6 +294,7 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
 // An abstract method may belong to many interfaces due to embedding.
 type Func struct {
        object
+       hasPtrRecv bool // only valid for methods that don't have a type yet
 }
 
 // NewFunc returns a new function with the given signature, representing
@@ -304,7 +305,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
        if sig != nil {
                typ = sig
        }
-       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}}
+       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false}
 }
 
 // FullName returns the package- or receiver-type-qualified name of
index ec7e4ed1c594452f813609194d8f6cb891647284..c2726f4dd2870d3c6308cee8bfbd06bbe7cdac27 100644 (file)
@@ -465,6 +465,8 @@ func (check *Checker) collectObjects() {
                        typ := unparen(list[0].Type)
                        if ptr, _ := typ.(*ast.StarExpr); ptr != nil {
                                typ = unparen(ptr.X)
+                               // TODO(gri): This may not be sufficient. See issue #27995.
+                               f.hasPtrRecv = true
                        }
                        if base, _ := typ.(*ast.Ident); base != nil {
                                // base is a potential base type name; determine
index 12c5c7b0a550308f9bb397e6d06f80b60b4b7106..bcdbc5906df73ce7b5174b62f3e4fa36e177c1a9 100644 (file)
@@ -558,9 +558,13 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
                        pos := name.Pos()
                        // Don't type-check signature yet - use an
                        // empty signature now and update it later.
-                       // Since we know the receiver, set it up now
-                       // (required to avoid crash in ptrRecv; see
-                       // e.g. test case for issue 6638).
+                       // But set up receiver since we know it and
+                       // its position, and because interface method
+                       // signatures don't get a receiver via regular
+                       // type-checking (there isn't a receiver in the
+                       // the method's AST). Setting the correct receiver
+                       // type is also important for ptrRecv() (see methodset.go).
+                       //
                        // TODO(gri) Consider marking methods signatures
                        // as incomplete, for better error messages. See
                        // also the T4 and T5 tests in testdata/cycles2.src.