From d014be43ae995b90135727583a015aa5b53e9baa Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Thu, 12 Jun 2014 18:05:33 -0400 Subject: [PATCH] go.tools/go/types: remove PackageObj Selection - not needed LGTM=gri R=gri CC=golang-codereviews https://golang.org/cl/105920043 --- go/loader/pkginfo.go | 5 +- go/ssa/builder.go | 115 +++++++++++++++++++----------------------- go/types/api.go | 3 +- go/types/call.go | 2 +- go/types/selection.go | 31 +++--------- refactor/eg/eg.go | 7 +-- refactor/eg/match.go | 6 +-- 7 files changed, 71 insertions(+), 98 deletions(-) diff --git a/go/loader/pkginfo.go b/go/loader/pkginfo.go index bbd3b26e..77e4b6af 100644 --- a/go/loader/pkginfo.go +++ b/go/loader/pkginfo.go @@ -78,8 +78,9 @@ func (info *PackageInfo) ObjectOf(id *ast.Ident) types.Object { func (info *PackageInfo) IsType(e ast.Expr) bool { switch e := e.(type) { case *ast.SelectorExpr: // pkg.Type - if sel := info.Selections[e]; sel.Kind() == types.PackageObj { - _, isType := sel.Obj().(*types.TypeName) + if _, ok := info.Selections[e]; !ok { + // qualified identifier + _, isType := info.Uses[e.Sel].(*types.TypeName) return isType } case *ast.StarExpr: // *T diff --git a/go/ssa/builder.go b/go/ssa/builder.go index cd3417ea..f01d088d 100644 --- a/go/ssa/builder.go +++ b/go/ssa/builder.go @@ -350,22 +350,20 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { return b.addr(fn, e.X, escaping) case *ast.SelectorExpr: - switch sel := fn.Pkg.info.Selections[e]; sel.Kind() { - case types.PackageObj: - obj := sel.Obj() - if v := fn.Prog.packageLevelValue(obj); v != nil { - return &address{addr: v, expr: e} - } - panic("undefined package-qualified name: " + obj.Name()) - - case types.FieldVal: - wantAddr := true - v := b.receiver(fn, e.X, wantAddr, escaping, sel) - last := len(sel.Index()) - 1 - return &address{ - addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()), - expr: e.Sel, - } + sel, ok := fn.Pkg.info.Selections[e] + if !ok { + // qualified identifier + return b.addr(fn, e.Sel, escaping) + } + if sel.Kind() != types.FieldVal { + panic(sel) + } + wantAddr := true + v := b.receiver(fn, e.X, wantAddr, escaping, sel) + last := len(sel.Index()) - 1 + return &address{ + addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()), + expr: e.Sel, } case *ast.IndexExpr: @@ -614,10 +612,12 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value { return emitLoad(fn, fn.lookup(obj, false)) // var (address) case *ast.SelectorExpr: - switch sel := fn.Pkg.info.Selections[e]; sel.Kind() { - case types.PackageObj: + sel, ok := fn.Pkg.info.Selections[e] + if !ok { + // qualified identifier return b.expr(fn, e.Sel) - + } + switch sel.Kind() { case types.MethodExpr: // (*T).f or T.f, the method f from the method-set of type T. // The result is a "thunk". @@ -749,47 +749,8 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { // Is this a method call? if selector, ok := unparen(e.Fun).(*ast.SelectorExpr); ok { - switch sel := fn.Pkg.info.Selections[selector]; sel.Kind() { - case types.PackageObj: - // e.g. fmt.Println - - case types.MethodExpr: - // T.f() or (*T).f(): a statically dispatched - // call to the method f in the method-set of T - // or *T. T may be an interface. - - // e.Fun would evaluate to a concrete method, - // interface wrapper function, or promotion - // wrapper. - // - // For now, we evaluate it in the usual way. - - // TODO(adonovan): opt: inline expr() here, to - // make the call static and to avoid - // generation of wrappers. It's somewhat - // tricky as it may consume the first actual - // parameter if the call is "invoke" mode. - // - // Examples: - // type T struct{}; func (T) f() {} // "call" mode - // type T interface { f() } // "invoke" mode - // - // type S struct{ T } - // - // var s S - // S.f(s) - // (*S).f(&s) - // - // Suggested approach: - // - consume the first actual parameter expression - // and build it with b.expr(). - // - apply implicit field selections. - // - use MethodVal logic to populate fields of c. - - case types.FieldVal: - // A field access, not a method call. - - case types.MethodVal: + sel, ok := fn.Pkg.info.Selections[selector] + if ok && sel.Kind() == types.MethodVal { obj := sel.Obj().(*types.Func) wantAddr := isPointer(recvType(obj)) escaping := true @@ -804,11 +765,37 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { c.Args = append(c.Args, v) } return - - default: - panic(fmt.Sprintf("illegal (%s).%s() call; X:%T", - fn.Pkg.typeOf(selector.X), selector.Sel.Name, selector.X)) } + + // sel.Kind()==MethodExpr indicates T.f() or (*T).f(): + // a statically dispatched call to the method f in the + // method-set of T or *T. T may be an interface. + // + // e.Fun would evaluate to a concrete method, interface + // wrapper function, or promotion wrapper. + // + // For now, we evaluate it in the usual way. + // + // TODO(adonovan): opt: inline expr() here, to make the + // call static and to avoid generation of wrappers. + // It's somewhat tricky as it may consume the first + // actual parameter if the call is "invoke" mode. + // + // Examples: + // type T struct{}; func (T) f() {} // "call" mode + // type T interface { f() } // "invoke" mode + // + // type S struct{ T } + // + // var s S + // S.f(s) + // (*S).f(&s) + // + // Suggested approach: + // - consume the first actual parameter expression + // and build it with b.expr(). + // - apply implicit field selections. + // - use MethodVal logic to populate fields of c. } // Evaluate the function operand in the usual way. diff --git a/go/types/api.go b/go/types/api.go index d7081f08..e35425f7 100644 --- a/go/types/api.go +++ b/go/types/api.go @@ -170,7 +170,8 @@ type Info struct { // Implicits map[ast.Node]Object - // Selections maps selector expressions to their corresponding selections. + // Selections maps selector expressions (excluding qualified identifiers) + // to their corresponding selections. Selections map[*ast.SelectorExpr]*Selection // Scopes maps ast.Nodes to the scopes they define. Package scopes are not diff --git a/go/types/call.go b/go/types/call.go index b8ee6d24..2ca943cf 100644 --- a/go/types/call.go +++ b/go/types/call.go @@ -267,7 +267,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { check.errorf(e.Pos(), "%s not exported by package %s", sel, ident) // ok to continue } - check.recordSelection(e, PackageObj, nil, exp, nil, false) + check.recordUse(e.Sel, exp) // Simplified version of the code for *ast.Idents: // - imported objects are always fully initialized switch exp := exp.(type) { diff --git a/go/types/selection.go b/go/types/selection.go index a85f0d1f..1c701655 100644 --- a/go/types/selection.go +++ b/go/types/selection.go @@ -11,14 +11,14 @@ import ( "fmt" ) -// SelectionKind describes the kind of a selector expression x.f. +// SelectionKind describes the kind of a selector expression x.f +// (excluding qualified identifiers). type SelectionKind int const ( FieldVal SelectionKind = iota // x.f is a struct field selector MethodVal // x.f is a method selector MethodExpr // x.f is a method expression - PackageObj // x.f is a qualified identifier ) // A Selection describes a selector expression x.f. @@ -36,33 +36,23 @@ const ( // p.x FieldVal T x int {0} true // p.m MethodVal *T m func (e *T) m() {1, 0} true // T.m MethodExpr T m func m(_ T) {1, 0} false -// math.Pi PackageObj nil Pi untyped numeric nil false // type Selection struct { kind SelectionKind - recv Type // type of x, nil if kind == PackageObj + recv Type // type of x obj Object // object denoted by x.f - index []int // path from x to x.f, nil if kind == PackageObj - indirect bool // set if there was any pointer indirection on the path, false if kind == PackageObj + index []int // path from x to x.f + indirect bool // set if there was any pointer indirection on the path } // Kind returns the selection kind. func (s *Selection) Kind() SelectionKind { return s.kind } // Recv returns the type of x in x.f. -// The result is nil if x.f is a qualified identifier (PackageObj). func (s *Selection) Recv() Type { return s.recv } -// Obj returns the object denoted by x.f. -// The following object types may appear: -// -// Kind Object -// -// FieldVal *Var field -// MethodVal *Func method -// MethodExpr *Func method -// PackageObj *Const, *Type, *Var, *Func imported const, type, var, or func -// +// Obj returns the object denoted by x.f; a *Var for +// a field selection, and a *Func in all other cases. func (s *Selection) Obj() Object { return s.obj } // Type returns the type of x.f, which may be different from the type of f. @@ -100,8 +90,6 @@ func (s *Selection) Type() Type { } // Index describes the path from x to f in x.f. -// The result is nil if x.f is a qualified identifier (PackageObj). -// // The last index entry is the field or method index of the type declaring f; // either: // @@ -115,7 +103,6 @@ func (s *Selection) Index() []int { return s.index } // Indirect reports whether any pointer indirection was required to get from // x to f in x.f. -// The result is false if x.f is a qualified identifier (PackageObj). func (s *Selection) Indirect() bool { return s.indirect } func (s *Selection) String() string { return SelectionString(nil, s) } @@ -128,7 +115,6 @@ func (s *Selection) String() string { return SelectionString(nil, s) } // "field (T) f int" // "method (T) f(X) Y" // "method expr (T) f(X) Y" -// "qualified ident var math.Pi float64" // func SelectionString(this *Package, s *Selection) string { var k string @@ -139,8 +125,6 @@ func SelectionString(this *Package, s *Selection) string { k = "method " case MethodExpr: k = "method expr " - case PackageObj: - return fmt.Sprintf("qualified ident %s", s.obj) default: unreachable() } @@ -150,7 +134,6 @@ func SelectionString(this *Package, s *Selection) string { WriteType(&buf, this, s.Recv()) fmt.Fprintf(&buf, ") %s", s.obj.Name()) if T := s.Type(); s.kind == FieldVal { - // TODO(adonovan): use "T.f" not "(T) f". buf.WriteByte(' ') WriteType(&buf, this, T) } else { diff --git a/refactor/eg/eg.go b/refactor/eg/eg.go index 76535aca..4bfcaa1f 100644 --- a/refactor/eg/eg.go +++ b/refactor/eg/eg.go @@ -244,9 +244,10 @@ func NewTransformer(fset *token.FileSet, template *loader.PackageInfo, verbose b // TODO reject dot-imports in pattern ast.Inspect(after, func(n ast.Node) bool { if n, ok := n.(*ast.SelectorExpr); ok { - sel := tr.info.Selections[n] - if sel.Kind() == types.PackageObj { - tr.importedObjs[sel.Obj()] = n + if _, ok := tr.info.Selections[n]; !ok { + // qualified ident + obj := tr.info.Uses[n.Sel] + tr.importedObjs[obj] = n return false // prune } } diff --git a/refactor/eg/match.go b/refactor/eg/match.go index 7476f9ac..0f328a90 100644 --- a/refactor/eg/match.go +++ b/refactor/eg/match.go @@ -217,9 +217,9 @@ func isRef(n ast.Node, info *loader.PackageInfo) types.Object { return info.Uses[n] case *ast.SelectorExpr: - sel := info.Selections[n] - if sel.Kind() == types.PackageObj { - return sel.Obj() + if _, ok := info.Selections[n]; !ok { + // qualified ident + return info.Uses[n.Sel] } } return nil