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:
parent
5efa8ff340
commit
f6f6621312
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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 = ©
|
sig = ©
|
||||||
}
|
}
|
||||||
var rtyp Type
|
var rtyp Type
|
||||||
if ptrRecv(m) {
|
if m.hasPtrRecv() {
|
||||||
rtyp = NewPointer(rbase)
|
rtyp = NewPointer(rbase)
|
||||||
} else {
|
} else {
|
||||||
rtyp = rbase
|
rtyp = rbase
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user