go.tools/go/types: remove Type.MethodSet() method.

Method-set caching is now performed externally using a MethodSetCache (if desired), not by the Types themselves.

This a minor deoptimization due to the extra maps, but avoids a situation in which method-sets are computed and frozen prematurely. (See b/7114)

LGTM=gri
R=gri
CC=golang-codereviews
https://golang.org/cl/61430045
diff --git a/go/gcimporter/gcimporter_test.go b/go/gcimporter/gcimporter_test.go
index 37b439a..877489b 100644
--- a/go/gcimporter/gcimporter_test.go
+++ b/go/gcimporter/gcimporter_test.go
@@ -207,7 +207,7 @@
 	}
 
 	mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
-	mset := types.NewPointer(mutex).MethodSet() // methods of *sync.Mutex
+	mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
 	sel := mset.Lookup(nil, "Lock")
 	lock := sel.Obj().(*types.Func)
 	if got, want := lock.Pkg().Path(), "sync"; got != want {
diff --git a/go/pointer/analysis.go b/go/pointer/analysis.go
index 1995c8d..4cc310b 100644
--- a/go/pointer/analysis.go
+++ b/go/pointer/analysis.go
@@ -278,7 +278,7 @@
 	if reflect := a.prog.ImportedPackage("reflect"); reflect != nil {
 		rV := reflect.Object.Scope().Lookup("Value")
 		a.reflectValueObj = rV
-		a.reflectValueCall = a.prog.Method(rV.Type().MethodSet().Lookup(nil, "Call"))
+		a.reflectValueCall = a.prog.Method(a.prog.MethodSets.MethodSet(rV.Type()).Lookup(nil, "Call"))
 		a.reflectType = reflect.Object.Scope().Lookup("Type").Type().(*types.Named)
 		a.reflectRtypeObj = reflect.Object.Scope().Lookup("rtype")
 		a.reflectRtypePtr = types.NewPointer(a.reflectRtypeObj.Type())
diff --git a/go/pointer/gen.go b/go/pointer/gen.go
index a9e1842..ce190d1 100644
--- a/go/pointer/gen.go
+++ b/go/pointer/gen.go
@@ -720,7 +720,7 @@
 	a.typeAssert(a.reflectRtypePtr, rtype, recv, true)
 
 	// Look up the concrete method.
-	meth := a.reflectRtypePtr.MethodSet().Lookup(call.Method.Pkg(), call.Method.Name())
+	meth := a.prog.MethodSets.MethodSet(a.reflectRtypePtr).Lookup(call.Method.Pkg(), call.Method.Name())
 	fn := a.prog.Method(meth)
 
 	obj := a.makeFunctionObject(fn, site) // new contour for this call
@@ -1209,7 +1209,7 @@
 
 // genMethodsOf generates nodes and constraints for all methods of type T.
 func (a *analysis) genMethodsOf(T types.Type) {
-	mset := T.MethodSet()
+	mset := a.prog.MethodSets.MethodSet(T)
 	for i, n := 0, mset.Len(); i < n; i++ {
 		a.valueNode(a.prog.Method(mset.At(i)))
 	}
diff --git a/go/pointer/reflect.go b/go/pointer/reflect.go
index 110cf06..ec71d9e 100644
--- a/go/pointer/reflect.go
+++ b/go/pointer/reflect.go
@@ -1568,7 +1568,7 @@
 
 		// We don't use Lookup(c.name) when c.name != "" to avoid
 		// ambiguity: >1 unexported methods could match.
-		mset := T.MethodSet()
+		mset := a.prog.MethodSets.MethodSet(T)
 		for i, n := 0, mset.Len(); i < n; i++ {
 			sel := mset.At(i)
 			if c.name == "" || c.name == sel.Obj().Name() {
diff --git a/go/pointer/solve.go b/go/pointer/solve.go
index bfd4f99..8ed4aee 100644
--- a/go/pointer/solve.go
+++ b/go/pointer/solve.go
@@ -312,7 +312,7 @@
 		}
 
 		// Look up the concrete method.
-		meth := tDyn.MethodSet().Lookup(c.method.Pkg(), c.method.Name())
+		meth := a.prog.MethodSets.MethodSet(tDyn).Lookup(c.method.Pkg(), c.method.Name())
 		if meth == nil {
 			panic(fmt.Sprintf("n%d: type %s has no method %s (iface=n%d)",
 				c.iface, tDyn, c.method, ifaceObj))
diff --git a/go/ssa/builder_test.go b/go/ssa/builder_test.go
index 03d77a0..8233224 100644
--- a/go/ssa/builder_test.go
+++ b/go/ssa/builder_test.go
@@ -104,7 +104,7 @@
 				if !isExt {
 					t.Fatalf("unexpected name type in main package: %s", mem)
 				}
-				mset := types.NewPointer(mem.Type()).MethodSet()
+				mset := prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
 				for i, n := 0, mset.Len(); i < n; i++ {
 					m := prog.Method(mset.At(i))
 					// For external types, only synthetic wrappers have code.
diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go
index 58194ef..19ece82 100644
--- a/go/ssa/interp/interp.go
+++ b/go/ssa/interp/interp.go
@@ -177,7 +177,7 @@
 	case errorType:
 		return i.errorMethods[meth.Id()]
 	}
-	return i.prog.Method(typ.MethodSet().Lookup(meth.Pkg(), meth.Name()))
+	return i.prog.Method(i.prog.MethodSets.MethodSet(typ).Lookup(meth.Pkg(), meth.Name()))
 }
 
 // visitInstr interprets a single ssa.Instruction within the activation
diff --git a/go/ssa/interp/reflect.go b/go/ssa/interp/reflect.go
index a297eff..6d42fd9 100644
--- a/go/ssa/interp/reflect.go
+++ b/go/ssa/interp/reflect.go
@@ -119,7 +119,7 @@
 
 func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
 	// Signature: func (t reflect.rtype) int
-	return args[0].(rtype).t.MethodSet().Len()
+	return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len()
 }
 
 func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
@@ -330,7 +330,7 @@
 
 func ext۰reflect۰Value۰NumMethod(fr *frame, args []value) value {
 	// Signature: func (reflect.Value) int
-	return rV2T(args[0]).t.MethodSet().Len()
+	return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len()
 }
 
 func ext۰reflect۰Value۰Pointer(fr *frame, args []value) value {
diff --git a/go/ssa/print.go b/go/ssa/print.go
index 9634fdb..a902382 100644
--- a/go/ssa/print.go
+++ b/go/ssa/print.go
@@ -407,7 +407,7 @@
 		case *Type:
 			fmt.Fprintf(buf, "  type  %-*s %s\n",
 				maxname, name, types.TypeString(p.Object, mem.Type().Underlying()))
-			for _, meth := range IntuitiveMethodSet(mem.Type()) {
+			for _, meth := range IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
 				fmt.Fprintf(buf, "    %s\n", types.SelectionString(p.Object, meth))
 			}
 
@@ -431,15 +431,15 @@
 //
 // TODO(gri): move this to go/types?
 //
-func IntuitiveMethodSet(T types.Type) []*types.Selection {
+func IntuitiveMethodSet(T types.Type, msets *types.MethodSetCache) []*types.Selection {
 	var result []*types.Selection
-	mset := T.MethodSet()
+	mset := msets.MethodSet(T)
 	if _, ok := T.Underlying().(*types.Interface); ok {
 		for i, n := 0, mset.Len(); i < n; i++ {
 			result = append(result, mset.At(i))
 		}
 	} else {
-		pmset := types.NewPointer(T).MethodSet()
+		pmset := msets.MethodSet(types.NewPointer(T))
 		for i, n := 0, pmset.Len(); i < n; i++ {
 			meth := pmset.At(i)
 			if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil {
diff --git a/go/ssa/promote.go b/go/ssa/promote.go
index 40ba77e..5b17e66 100644
--- a/go/ssa/promote.go
+++ b/go/ssa/promote.go
@@ -54,7 +54,7 @@
 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
 //
 func (prog *Program) makeMethods(T types.Type) bool {
-	tmset := T.MethodSet()
+	tmset := prog.MethodSets.MethodSet(T)
 	n := tmset.Len()
 	if n == 0 {
 		return false // empty (common case)
diff --git a/go/ssa/source.go b/go/ssa/source.go
index 6dd667e..c98dae8 100644
--- a/go/ssa/source.go
+++ b/go/ssa/source.go
@@ -119,7 +119,7 @@
 				return mem
 			}
 		case *Type:
-			mset := types.NewPointer(mem.Type()).MethodSet()
+			mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
 			for i, n := 0, mset.Len(); i < n; i++ {
 				// Don't call Program.Method: avoid creating wrappers.
 				obj := mset.At(i).Obj().(*types.Func)
@@ -202,7 +202,7 @@
 		return v.(*Function)
 	}
 	// Interface method wrapper?
-	meth := recvType(obj).MethodSet().Lookup(obj.Pkg(), obj.Name())
+	meth := prog.MethodSets.MethodSet(recvType(obj)).Lookup(obj.Pkg(), obj.Name())
 	return prog.Method(meth)
 }
 
diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go
index 1b153c9..cfa06e5 100644
--- a/go/ssa/ssa.go
+++ b/go/ssa/ssa.go
@@ -22,10 +22,11 @@
 // A Program is a partial or complete Go program converted to SSA form.
 //
 type Program struct {
-	Fset     *token.FileSet              // position information for the files of this Program
-	imported map[string]*Package         // all importable Packages, keyed by import path
-	packages map[*types.Package]*Package // all loaded Packages, keyed by object
-	mode     BuilderMode                 // set of mode bits for SSA construction
+	Fset       *token.FileSet              // position information for the files of this Program
+	imported   map[string]*Package         // all importable Packages, keyed by import path
+	packages   map[*types.Package]*Package // all loaded Packages, keyed by object
+	mode       BuilderMode                 // set of mode bits for SSA construction
+	MethodSets types.MethodSetCache        // cache of type-checker's method-sets
 
 	methodsMu           sync.Mutex                // guards the following maps:
 	methodSets          typemap.M                 // maps type to its concrete methodSet
@@ -612,8 +613,8 @@
 // MakeInterface constructs an instance of an interface type from a
 // value of a concrete type.
 //
-// Use X.Type().MethodSet() to find the method-set of X, and
-// Program.Method(m) to find the implementation of a method.
+// Use Program.MethodSets.MethodSet(X.Type()) to find the method-set
+// of X, and Program.Method(m) to find the implementation of a method.
 //
 // To construct the zero value of an interface type T, use:
 // 	NewConst(exact.MakeNil(), T, pos)
diff --git a/go/ssa/ssautil/visit.go b/go/ssa/ssautil/visit.go
index f202148..6b8c5d2 100644
--- a/go/ssa/ssautil/visit.go
+++ b/go/ssa/ssautil/visit.go
@@ -42,7 +42,7 @@
 		}
 	}
 	for _, T := range visit.prog.TypesWithMethodSets() {
-		mset := T.MethodSet()
+		mset := visit.prog.MethodSets.MethodSet(T)
 		for i, n := 0, mset.Len(); i < n; i++ {
 			visit.function(visit.prog.Method(mset.At(i)))
 		}
diff --git a/go/types/call.go b/go/types/call.go
index 823693d..2773e90 100644
--- a/go/types/call.go
+++ b/go/types/call.go
@@ -392,7 +392,7 @@
 				// TODO(gri) Consider also using a method set cache for the lifetime
 				// of checker once we rely on MethodSet lookup instead of individual
 				// lookup.
-				mset := typ.MethodSet()
+				mset := NewMethodSet(typ)
 				if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
 					check.dump("%s: (%s).%v -> %s", e.Pos(), typ, obj.name, m)
 					check.dump("%s\n", mset)
diff --git a/go/types/methodset.go b/go/types/methodset.go
index 4ecd6f5..9ded496 100644
--- a/go/types/methodset.go
+++ b/go/types/methodset.go
@@ -10,7 +10,6 @@
 	"bytes"
 	"fmt"
 	"sort"
-	"sync"
 )
 
 // A MethodSet is an ordered set of concrete or abstract (interface) methods;
@@ -63,31 +62,11 @@
 // Shared empty method set.
 var emptyMethodSet MethodSet
 
-// A cachedMethodSet provides access to a method set
-// for a given type by computing it once on demand,
-// and then caching it for future use. Threadsafe.
-type cachedMethodSet struct {
-	mset *MethodSet
-	mu   sync.RWMutex // protects mset
-}
-
-// Of returns the (possibly cached) method set for typ.
-// Threadsafe.
-func (c *cachedMethodSet) of(typ Type) *MethodSet {
-	c.mu.RLock()
-	mset := c.mset
-	c.mu.RUnlock()
-	if mset == nil {
-		mset = NewMethodSet(typ)
-		c.mu.Lock()
-		c.mset = mset
-		c.mu.Unlock()
-	}
-	return mset
-}
-
-// NewMethodSet computes the method set for the given type T.
-// It always returns a non-nil method set, even if it is empty.
+// NewMethodSet returns the method set for the given type T.  It
+// always returns a non-nil method set, even if it is empty.
+//
+// A MethodSetCache handles repeat queries more efficiently.
+//
 func NewMethodSet(T Type) *MethodSet {
 	// WARNING: The code in this function is extremely subtle - do not modify casually!
 	//          This function and lookupFieldOrMethod should be kept in sync.
diff --git a/go/types/methodsetcache.go b/go/types/methodsetcache.go
new file mode 100644
index 0000000..5a482e9
--- /dev/null
+++ b/go/types/methodsetcache.go
@@ -0,0 +1,69 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a cache of method sets.
+
+package types
+
+import "sync"
+
+// A MethodSetCache records the method set of each type T for which
+// MethodSet(T) is called so that repeat queries are fast.
+// The zero value is a ready-to-use cache instance.
+type MethodSetCache struct {
+	mu     sync.Mutex
+	named  map[*Named]struct{ value, pointer *MethodSet } // method sets for named N and *N
+	others map[Type]*MethodSet                            // all other types
+}
+
+// MethodSet returns the method set of type T.  It is thread-safe.
+//
+// If cache is nil, this function is equivalent to NewMethodSet(T).
+// Utility functions can thus expose an optional *MethodSetCache
+// parameter to clients that care about performance.
+//
+func (cache *MethodSetCache) MethodSet(T Type) *MethodSet {
+	if cache == nil {
+		return NewMethodSet(T)
+	}
+	cache.mu.Lock()
+	defer cache.mu.Unlock()
+
+	switch T := T.(type) {
+	case *Named:
+		return cache.lookupNamed(T).value
+
+	case *Pointer:
+		if N, ok := T.Elem().(*Named); ok {
+			return cache.lookupNamed(N).pointer
+		}
+	}
+
+	// all other types
+	// (The map uses pointer equivalence, not type identity.)
+	mset := cache.others[T]
+	if mset == nil {
+		mset = NewMethodSet(T)
+		if cache.others == nil {
+			cache.others = make(map[Type]*MethodSet)
+		}
+		cache.others[T] = mset
+	}
+	return mset
+}
+
+func (cache *MethodSetCache) lookupNamed(named *Named) struct{ value, pointer *MethodSet } {
+	if cache.named == nil {
+		cache.named = make(map[*Named]struct{ value, pointer *MethodSet })
+	}
+	// Avoid recomputing mset(*T) for each distinct Pointer
+	// instance whose underlying type is a named type.
+	msets, ok := cache.named[named]
+	if !ok {
+		msets.value = NewMethodSet(named)
+		msets.pointer = NewMethodSet(NewPointer(named))
+		cache.named[named] = msets
+	}
+	return msets
+}
diff --git a/go/types/type.go b/go/types/type.go
index 0a0b22e..5aeb416 100644
--- a/go/types/type.go
+++ b/go/types/type.go
@@ -14,9 +14,6 @@
 	// Underlying returns the underlying type of a type.
 	Underlying() Type
 
-	// MethodSet returns the method set of a type.
-	MethodSet() *MethodSet
-
 	// String returns a string representation of a type.
 	String() string
 }
@@ -126,8 +123,7 @@
 	fields []*Var
 	tags   []string // field tags; nil if there are no tags
 	// TODO(gri) access to offsets is not threadsafe - fix this
-	offsets []int64         // field offsets in bytes, lazily initialized
-	mset    cachedMethodSet // method set, lazily initialized
+	offsets []int64 // field offsets in bytes, lazily initialized
 }
 
 // NewStruct returns a new struct with the given fields and corresponding field tags.
@@ -163,8 +159,7 @@
 
 // A Pointer represents a pointer type.
 type Pointer struct {
-	base Type            // element type
-	mset cachedMethodSet // method set, lazily initialized
+	base Type // element type
 }
 
 // NewPointer returns a new pointer type for the given element (base) type.
@@ -249,8 +244,7 @@
 	methods   []*Func  // ordered list of explicitly declared methods
 	embeddeds []*Named // ordered list of explicitly embedded types
 
-	allMethods []*Func         // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
-	mset       cachedMethodSet // method set for interface, lazily initialized
+	allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
 }
 
 // NewInterface returns a new interface for the given methods and embedded types.
@@ -364,10 +358,9 @@
 
 // A Named represents a named type.
 type Named struct {
-	obj         *TypeName       // corresponding declared object
-	underlying  Type            // possibly a *Named during setup; never a *Named once set up completely
-	methods     []*Func         // methods declared for this type (not the method set of this type)
-	mset, pmset cachedMethodSet // method set for T, *T, lazily initialized
+	obj        *TypeName // corresponding declared object
+	underlying Type      // possibly a *Named during setup; never a *Named once set up completely
+	methods    []*Func   // methods declared for this type (not the method set of this type)
 }
 
 // NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@ -426,25 +419,6 @@
 func (t *Chan) Underlying() Type      { return t }
 func (t *Named) Underlying() Type     { return t.underlying }
 
-func (t *Basic) MethodSet() *MethodSet  { return &emptyMethodSet }
-func (t *Array) MethodSet() *MethodSet  { return &emptyMethodSet }
-func (t *Slice) MethodSet() *MethodSet  { return &emptyMethodSet }
-func (t *Struct) MethodSet() *MethodSet { return t.mset.of(t) }
-func (t *Pointer) MethodSet() *MethodSet {
-	if named, _ := t.base.(*Named); named != nil {
-		// Avoid recomputing mset(*T) for each distinct Pointer
-		// instance whose underlying type is a named type.
-		return named.pmset.of(t)
-	}
-	return t.mset.of(t)
-}
-func (t *Tuple) MethodSet() *MethodSet     { return &emptyMethodSet }
-func (t *Signature) MethodSet() *MethodSet { return &emptyMethodSet }
-func (t *Interface) MethodSet() *MethodSet { return t.mset.of(t) }
-func (t *Map) MethodSet() *MethodSet       { return &emptyMethodSet }
-func (t *Chan) MethodSet() *MethodSet      { return &emptyMethodSet }
-func (t *Named) MethodSet() *MethodSet     { return t.mset.of(t) }
-
 func (t *Basic) String() string     { return TypeString(nil, t) }
 func (t *Array) String() string     { return TypeString(nil, t) }
 func (t *Slice) String() string     { return TypeString(nil, t) }