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:
Robert Griesemer 2013-07-19 14:46:28 -07:00
parent 5d7d9091bb
commit b0ae7702cb
4 changed files with 62 additions and 20 deletions

View File

@ -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)

View File

@ -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

View File

@ -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
} }

View File

@ -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
} }
} }