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)
|
check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
check.recordObject(arg.Sel, lookupResult(base, obj, index, indirect))
|
||||||
offs := check.conf.offsetof(base, index)
|
offs := check.conf.offsetof(base, index)
|
||||||
x.mode = constant
|
x.mode = constant
|
||||||
x.val = exact.MakeInt64(offs)
|
x.val = exact.MakeInt64(offs)
|
||||||
|
|
|
@ -225,7 +225,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
check.recordObject(e.Sel, obj)
|
check.recordObject(e.Sel, lookupResult(x.typ, obj, index, indirect))
|
||||||
|
|
||||||
if x.mode == typexpr {
|
if x.mode == typexpr {
|
||||||
// method expression
|
// method expression
|
||||||
|
|
|
@ -11,6 +11,26 @@ package types
|
||||||
// types always have only one representation (even when imported
|
// types always have only one representation (even when imported
|
||||||
// indirectly via different packages.)
|
// 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
|
// LookupFieldOrMethod looks up a field or method with given package and name
|
||||||
// in typ and returns the corresponding *Var or *Func, an index sequence,
|
// 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
|
// 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.
|
// A concrete type implements T if it implements all methods of T.
|
||||||
for _, m := range T.methods {
|
for _, m := range T.methods {
|
||||||
obj, _, indirect := LookupFieldOrMethod(typ, m.pkg, m.name)
|
obj, _, indirect := lookupFieldOrMethod(typ, m.pkg, m.name)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return m, false
|
return m, false
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,34 +13,55 @@ import (
|
||||||
"sync"
|
"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.
|
// TODO(gri) Method.Type() returns the wrong receiver type.
|
||||||
|
|
||||||
// A Method represents a concrete or abstract (interface)
|
// A Method represents a concrete or abstract (interface) method x.m
|
||||||
// method of a method set.
|
// and corresponding path. The method belongs to the method set of x.
|
||||||
type Method struct {
|
type Method struct {
|
||||||
*Func
|
*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
|
recv Type
|
||||||
index []int
|
index []int
|
||||||
indirect bool
|
indirect bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recv returns the receiver type for m, which is the type
|
// Recv returns the type of x for the path p for x.f.
|
||||||
// for which the method set containing m was computed. For
|
func (p *selectorPath) Recv() Type { return p.recv }
|
||||||
// interface methods, the receiver type is the type of the
|
|
||||||
// interface.
|
|
||||||
func (m *Method) Recv() Type { return m.recv }
|
|
||||||
|
|
||||||
// Index describes the path to the concrete (possibly embedded)
|
// Index describes the path from x to the concrete (possibly embedded) field
|
||||||
// function implementing this method. See LookupFieldOrMethod
|
// or method f for the path p for x.f.
|
||||||
// for details.
|
//
|
||||||
func (m *Method) Index() []int { return m.index }
|
// 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
|
// Indirect reports whether any pointer indirection was required to get from
|
||||||
// required to get from a value of m's receiver type to
|
// a value x to f for the path p for x.f.
|
||||||
// the receiver type of the concrete function implementing m.
|
func (p *selectorPath) Indirect() bool { return p.indirect }
|
||||||
// For interface methods, Indirect is undefined.
|
|
||||||
func (m *Method) Indirect() bool { return m.indirect }
|
|
||||||
|
|
||||||
// A MethodSet is an ordered set of concrete or abstract (interface) methods.
|
// 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.
|
// 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 f is not in the set, add it
|
||||||
if !multiples {
|
if !multiples {
|
||||||
if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue