go.tools/ssa: (another) major refactoring of method-set logic.
We now use LookupFieldOrMethod for all SelectorExprs, and
simplify the logic to discriminate the various cases.
We inline static calls to promoted/indirected functions,
dramatically reducing the number of functions created.
More tests are needed, but I'd like to submit this as-is.
In this CL, we:
- rely less on Id strings. Internally we now use
*types.Method (and its components) almost everywhere.
- stop thinking of types.Methods as objects. They don't
have stable identities. (Hopefully they will become
plain-old structs soon.)
- eliminate receiver indirection wrappers:
indirection and promotion are handled together by makeWrapper.
- Handle the interactions of promotion, indirection and
abstract methods much more cleanly.
- support receiver-bound interface method closures.
- break up builder.selectField so we can re-use parts
(emitFieldSelection).
- add importer.PackageInfo.classifySelector utility.
- delete interfaceMethodIndex()
- delete namedTypeMethodIndex()
- delete isSuperInterface() (replaced by types.IsAssignable)
- call memberFromObject on each declared concrete method's
*types.Func, not on every Method frem each method set, in the
CREATE phase for packages loaded by gcimporter.
go/types:
- document Func, Signature.Recv() better.
- use fmt in {Package,Label}.String
- reimplement Func.String to be prettier and to include method
receivers.
API changes:
- Function.method now holds the types.Method (soon to be
not-an-object) for synthetic wrappers.
- CallCommon.Method now contains an abstract (interface)
method object; was an abstract method index.
- CallCommon.MethodId() gone.
- Program.LookupMethod now takes a *Method not an Id string.
R=gri
CC=golang-dev
https://golang.org/cl/11674043
diff --git a/ssa/ssa.go b/ssa/ssa.go
index 514c38f..7a73913 100644
--- a/ssa/ssa.go
+++ b/ssa/ssa.go
@@ -22,13 +22,12 @@
PackagesByPath map[string]*Package // all loaded Packages, keyed by import path
packages map[*types.Package]*Package // all loaded Packages, keyed by object
builtins map[types.Object]*Builtin // all built-in functions, keyed by typechecker objects.
- concreteMethods map[*types.Func]*Function // maps named concrete methods to their code
+ concreteMethods map[*types.Func]*Function // maps declared concrete methods to their code
mode BuilderMode // set of mode bits for SSA construction
methodsMu sync.Mutex // guards the following maps:
methodSets typemap.M // maps type to its concrete MethodSet
- indirectionWrappers map[*Function]*Function // func(*T) wrappers for T-methods
- boundMethodWrappers map[*Function]*Function // wrappers for curried x.Method closures
+ boundMethodWrappers map[*types.Func]*Function // wrappers for curried x.Method closures
ifaceMethodWrappers map[*types.Func]*Function // wrappers for curried I.Method functions
}
@@ -73,6 +72,10 @@
// The keys of a method set are strings returned by the types.Id()
// function.
//
+// TODO(adonovan): encapsulate the representation behind both Id-based
+// and types.Method-based accessors and enable lazy population.
+// Perhaps hide it entirely within the Program API.
+//
type MethodSet map[string]*Function
// A Type is a Member of a Package representing a package-level named type.
@@ -250,7 +253,8 @@
//
type Function struct {
name string
- object types.Object // a *types.Func; may be nil for init, wrappers, etc.
+ object types.Object // a declared *types.Func; nil for init, wrappers, etc.
+ method *types.Method // info about provenance of synthetic methods [currently unused]
Signature *types.Signature
pos token.Pos
@@ -1177,7 +1181,7 @@
// Each CallCommon exists in one of two modes, function call and
// interface method invocation, or "call" and "invoke" for short.
//
-// 1. "call" mode: when Recv is nil (!IsInvoke), a CallCommon
+// 1. "call" mode: when Method is nil (!IsInvoke), a CallCommon
// represents an ordinary function call of the value in Func.
//
// In the common case in which Func is a *Function, this indicates a
@@ -1197,10 +1201,10 @@
// go t3()
// defer t5(...t6)
//
-// 2. "invoke" mode: when Recv is non-nil (IsInvoke), a CallCommon
+// 2. "invoke" mode: when Method is non-nil (IsInvoke), a CallCommon
// represents a dynamically dispatched call to an interface method.
-// In this mode, Recv is the interface value and Method is the index
-// of the method within the interface type of the receiver.
+// In this mode, Recv is the interface value and Method is the
+// interface's abstract method.
//
// Recv is implicitly supplied to the concrete method implementation
// as the receiver parameter; in other words, Args[0] holds not the
@@ -1219,17 +1223,18 @@
// readability of the printed form.)
//
type CallCommon struct {
- Recv Value // receiver, iff interface method invocation
- Method int // index of interface method; call MethodId() for its Id
- Func Value // target of call, iff function call
- Args []Value // actual parameters, including receiver in invoke mode
- HasEllipsis bool // true iff last Args is a slice of '...' args (needed?)
- pos token.Pos // position of CallExpr.Lparen, iff explicit in source
+ // TODO(adonovan): combine Recv/Func fields since Method now discriminates.
+ Recv Value // receiver (in "invoke" mode)
+ Method *types.Func // abstract method (in "invoke" mode)
+ Func Value // target of call (in "call" mode)
+ Args []Value // actual parameters, including receiver in invoke mode
+ HasEllipsis bool // true iff last Args is a slice of '...' args (needed?)
+ pos token.Pos // position of CallExpr.Lparen, iff explicit in source
}
// IsInvoke returns true if this call has "invoke" (not "call") mode.
func (c *CallCommon) IsInvoke() bool {
- return c.Recv != nil
+ return c.Method != nil
}
func (c *CallCommon) Pos() token.Pos { return c.pos }
@@ -1245,9 +1250,8 @@
// Signature returns nil for a call to a built-in function.
//
func (c *CallCommon) Signature() *types.Signature {
- if c.Recv != nil {
- iface := c.Recv.Type().Underlying().(*types.Interface)
- return iface.Method(c.Method).Type().(*types.Signature)
+ if c.Method != nil {
+ return c.Method.Type().(*types.Signature)
}
sig, _ := c.Func.Type().Underlying().(*types.Signature) // nil for *Builtin
return sig
@@ -1265,12 +1269,6 @@
return nil
}
-// MethodId returns the Id for the method called by c, which must
-// have "invoke" mode.
-func (c *CallCommon) MethodId() string {
- return c.Recv.Type().Underlying().(*types.Interface).Method(c.Method).Id()
-}
-
// Description returns a description of the mode of this call suitable
// for a user interface, e.g. "static method call".
func (c *CallCommon) Description() string {