1
0
mirror of https://github.com/golang/go synced 2024-11-17 06:24:48 -07:00

go/types: make ptrRecv a method hasPtrRecv of Func

This is a clean port of CL 351310 from types2 to go/types
with the necessary changes to methodset.go which doesn't
exist in types2.

Change-Id: Ifdac820d3be14c7bfa778b7bca3f6ba58d220b2e
Reviewed-on: https://go-review.googlesource.com/c/go/+/351311
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-09-21 11:25:59 -07:00
parent 5efa8ff340
commit f6f6621312
5 changed files with 27 additions and 27 deletions

View File

@ -212,7 +212,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// is shorthand for (&x).m()". // is shorthand for (&x).m()".
if f, _ := obj.(*Func); f != nil { if f, _ := obj.(*Func); f != nil {
// determine if method has a pointer receiver // determine if method has a pointer receiver
hasPtrRecv := tpar == nil && ptrRecv(f) hasPtrRecv := tpar == nil && f.hasPtrRecv()
if hasPtrRecv && !indirect && !addressable { if hasPtrRecv && !indirect && !addressable {
return nil, nil, true // pointer/addressable receiver required return nil, nil, true // pointer/addressable receiver required
} }

View File

@ -232,10 +232,10 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
// if f is not in the set, add it // if f is not in the set, add it
if !multiples { if !multiples {
// TODO(gri) A found method may not be added because it's not in the method set // TODO(gri) A found method may not be added because it's not in the method set
// (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method // (!indirect && f.hasPtrRecv()). A 2nd method on the same level may be in the method
// set and may not collide with the first one, thus leading to a false positive. // set and may not collide with the first one, thus leading to a false positive.
// Is that possible? Investigate. // Is that possible? Investigate.
if _, found := s[key]; !found && (indirect || !ptrRecv(f)) { if _, found := s[key]; !found && (indirect || !f.hasPtrRecv()) {
s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect} s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
continue continue
} }
@ -244,22 +244,3 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
} }
return s return s
} }
// ptrRecv reports whether the receiver is of the form *T.
func ptrRecv(f *Func) bool {
// If a method's receiver type is set, use that as the source of truth for the receiver.
// Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
// signature. We may reach here before the signature is fully set up: we must explicitly
// check if the receiver is set (we cannot just look for non-nil f.typ).
if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
_, isPtr := deref(sig.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
}

View File

@ -257,7 +257,7 @@ func expandNamed(env *Environment, n *Named, instPos token.Pos) (tparams *TypePa
// During type checking origm may not have a fully set up type, so defer // During type checking origm may not have a fully set up type, so defer
// instantiation of its signature until later. // instantiation of its signature until later.
m := NewFunc(origm.pos, origm.pkg, origm.name, nil) m := NewFunc(origm.pos, origm.pkg, origm.name, nil)
m.hasPtrRecv = ptrRecv(origm) m.hasPtrRecv_ = origm.hasPtrRecv()
// Setting instRecv here allows us to complete later (we need the // Setting instRecv here allows us to complete later (we need the
// instRecv to get targs and the original method). // instRecv to get targs and the original method).
m.instRecv = n m.instRecv = n
@ -316,7 +316,7 @@ func (check *Checker) completeMethod(env *Environment, m *Func) {
sig = &copy sig = &copy
} }
var rtyp Type var rtyp Type
if ptrRecv(m) { if m.hasPtrRecv() {
rtyp = NewPointer(rbase) rtyp = NewPointer(rbase)
} else { } else {
rtyp = rbase rtyp = rbase

View File

@ -317,8 +317,8 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
// An abstract method may belong to many interfaces due to embedding. // An abstract method may belong to many interfaces due to embedding.
type Func struct { type Func struct {
object object
instRecv *Named // if non-nil, the receiver type for an incomplete instance method instRecv *Named // if non-nil, the receiver type for an incomplete instance method
hasPtrRecv bool // only valid for methods that don't have a type yet hasPtrRecv_ bool // only valid for methods that don't have a type yet; use hasPtrRecv() to read
} }
// NewFunc returns a new function with the given signature, representing // NewFunc returns a new function with the given signature, representing
@ -343,6 +343,25 @@ func (obj *Func) FullName() string {
// Scope returns the scope of the function's body block. // Scope returns the scope of the function's body block.
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope } func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
// hasPtrRecv reports whether the receiver is of the form *T for the given method obj.
func (obj *Func) hasPtrRecv() bool {
// If a method's receiver type is set, use that as the source of truth for the receiver.
// Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
// signature. We may reach here before the signature is fully set up: we must explicitly
// check if the receiver is set (we cannot just look for non-nil obj.typ).
if sig, _ := obj.typ.(*Signature); sig != nil && sig.recv != nil {
_, isPtr := deref(sig.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 obj.hasPtrRecv_
}
func (*Func) isDependency() {} // a function may be a dependency of an initialization expression func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
// A Label represents a declared label. // A Label represents a declared label.

View File

@ -483,7 +483,7 @@ func (check *Checker) collectObjects() {
// Determine the receiver base type and associate m with it. // Determine the receiver base type and associate m with it.
ptr, base := check.resolveBaseTypeName(m.ptr, m.recv) ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
if base != nil { if base != nil {
m.obj.hasPtrRecv = ptr m.obj.hasPtrRecv_ = ptr
check.methods[base] = append(check.methods[base], m.obj) check.methods[base] = append(check.methods[base], m.obj)
} }
} }