go.tools/go/types: record Field/Method object for f in selector expressions x.f
TODO(gri) This needs tests. R=adonovan CC=golang-dev https://golang.org/cl/11519046
This commit is contained in:
parent
5d7d9091bb
commit
b0ae7702cb
|
@ -355,6 +355,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin) {
|
|||
check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
|
||||
goto Error
|
||||
}
|
||||
check.recordObject(arg.Sel, lookupResult(base, obj, index, indirect))
|
||||
offs := check.conf.offsetof(base, index)
|
||||
x.mode = constant
|
||||
x.val = exact.MakeInt64(offs)
|
||||
|
|
|
@ -225,7 +225,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
goto Error
|
||||
}
|
||||
|
||||
check.recordObject(e.Sel, obj)
|
||||
check.recordObject(e.Sel, lookupResult(x.typ, obj, index, indirect))
|
||||
|
||||
if x.mode == typexpr {
|
||||
// method expression
|
||||
|
|
|
@ -11,6 +11,26 @@ package types
|
|||
// types always have only one representation (even when imported
|
||||
// indirectly via different packages.)
|
||||
|
||||
// TODO(gri) Move Field to objects.go?
|
||||
|
||||
// A Field represents a struct field x.f and corresponding path.
|
||||
type Field struct {
|
||||
*Var
|
||||
selectorPath
|
||||
}
|
||||
|
||||
func lookupResult(typ Type, obj Object, index []int, indirect bool) Object {
|
||||
switch obj := obj.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
case *Var:
|
||||
return &Field{obj, selectorPath{typ, index, indirect}}
|
||||
case *Func:
|
||||
return &Method{obj, selectorPath{typ, index, indirect}}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// LookupFieldOrMethod looks up a field or method with given package and name
|
||||
// in typ and returns the corresponding *Var or *Func, an index sequence,
|
||||
// and a bool indicating if there were any pointer indirections on the path
|
||||
|
@ -249,7 +269,7 @@ func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) {
|
|||
|
||||
// A concrete type implements T if it implements all methods of T.
|
||||
for _, m := range T.methods {
|
||||
obj, _, indirect := LookupFieldOrMethod(typ, m.pkg, m.name)
|
||||
obj, _, indirect := lookupFieldOrMethod(typ, m.pkg, m.name)
|
||||
if obj == nil {
|
||||
return m, false
|
||||
}
|
||||
|
|
|
@ -13,34 +13,55 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// TODO(gri) Move Method and accessors to objects.go.
|
||||
// TODO(gri) Move Method to objects.go?
|
||||
// TODO(gri) Method.Type() returns the wrong receiver type.
|
||||
|
||||
// A Method represents a concrete or abstract (interface)
|
||||
// method of a method set.
|
||||
// A Method represents a concrete or abstract (interface) method x.m
|
||||
// and corresponding path. The method belongs to the method set of x.
|
||||
type Method struct {
|
||||
*Func
|
||||
selectorPath
|
||||
}
|
||||
|
||||
// Type returns the promoted signature type of m (i.e., the receiver
|
||||
// type is Recv()).
|
||||
func (m *Method) Type() Type {
|
||||
sig := *m.Func.typ.(*Signature)
|
||||
recv := *sig.recv
|
||||
recv.typ = m.recv
|
||||
sig.recv = &recv
|
||||
return &sig
|
||||
}
|
||||
|
||||
// A selectorPath describes the path from a value x to one of its fields
|
||||
// or methods f for a selector expression x.f. A path may include implicit
|
||||
// field selections (e.g., x.f may be x.a.b.c.f).
|
||||
type selectorPath struct {
|
||||
recv Type
|
||||
index []int
|
||||
indirect bool
|
||||
}
|
||||
|
||||
// Recv returns the receiver type for m, which is the type
|
||||
// for which the method set containing m was computed. For
|
||||
// interface methods, the receiver type is the type of the
|
||||
// interface.
|
||||
func (m *Method) Recv() Type { return m.recv }
|
||||
// Recv returns the type of x for the path p for x.f.
|
||||
func (p *selectorPath) Recv() Type { return p.recv }
|
||||
|
||||
// Index describes the path to the concrete (possibly embedded)
|
||||
// function implementing this method. See LookupFieldOrMethod
|
||||
// for details.
|
||||
func (m *Method) Index() []int { return m.index }
|
||||
// Index describes the path from x to the concrete (possibly embedded) field
|
||||
// or method f for the path p for x.f.
|
||||
//
|
||||
// The last index entry is the field or method index of the type declaring f;
|
||||
// either:
|
||||
//
|
||||
// 1) the list of declared methods of a named type; or
|
||||
// 2) the list of methods of an interface type; or
|
||||
// 3) the list of fields of a struct type.
|
||||
//
|
||||
// The earlier index entries are the indices of the embedded fields implicitly
|
||||
// traversed to get from (the type of) x to f, starting at embedding depth 0.
|
||||
func (p *selectorPath) Index() []int { return p.index }
|
||||
|
||||
// Indirect reports whether any pointer indirections was
|
||||
// required to get from a value of m's receiver type to
|
||||
// the receiver type of the concrete function implementing m.
|
||||
// For interface methods, Indirect is undefined.
|
||||
func (m *Method) Indirect() bool { return m.indirect }
|
||||
// Indirect reports whether any pointer indirection was required to get from
|
||||
// a value x to f for the path p for x.f.
|
||||
func (p *selectorPath) Indirect() bool { return p.indirect }
|
||||
|
||||
// A MethodSet is an ordered set of concrete or abstract (interface) methods.
|
||||
// The zero value for a MethodSet is a ready-to-use empty method set.
|
||||
|
@ -279,7 +300,7 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
|
|||
// if f is not in the set, add it
|
||||
if !multiples {
|
||||
if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
|
||||
s[key] = &Method{Func: f, index: concat(index, i), indirect: indirect}
|
||||
s[key] = &Method{f, selectorPath{index: concat(index, i), indirect: indirect}}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue