--- /dev/null
+package unused
+
+import "go/types"
+
+// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
+func lookupMethod(T *types.Interface, pkg *types.Package, name string) (int, *types.Func) {
+ if name != "_" {
+ for i := 0; i < T.NumMethods(); i++ {
+ m := T.Method(i)
+ if sameId(m, pkg, name) {
+ return i, m
+ }
+ }
+ }
+ return -1, nil
+}
+
+func sameId(obj types.Object, pkg *types.Package, name string) bool {
+ // spec:
+ // "Two identifiers are different if they are spelled differently,
+ // or if they appear in different packages and are not exported.
+ // Otherwise, they are the same."
+ if name != obj.Name() {
+ return false
+ }
+ // obj.Name == name
+ if obj.Exported() {
+ return true
+ }
+ // not exported, so packages must be the same (pkg == nil for
+ // fields in Universe scope; this can only happen for types
+ // introduced via Eval)
+ if pkg == nil || obj.Pkg() == nil {
+ return pkg == obj.Pkg()
+ }
+ // pkg != nil && obj.pkg != nil
+ return pkg.Path() == obj.Pkg().Path()
+}
+
+func (g *Graph) implements(V types.Type, T *types.Interface, msV *types.MethodSet) ([]*types.Selection, bool) {
+ // fast path for common case
+ if T.Empty() {
+ return nil, true
+ }
+
+ if ityp, _ := V.Underlying().(*types.Interface); ityp != nil {
+ // TODO(dh): is this code reachable?
+ for i := 0; i < T.NumMethods(); i++ {
+ m := T.Method(i)
+ _, obj := lookupMethod(ityp, m.Pkg(), m.Name())
+ switch {
+ case obj == nil:
+ return nil, false
+ case !types.Identical(obj.Type(), m.Type()):
+ return nil, false
+ }
+ }
+ return nil, true
+ }
+
+ // A concrete type implements T if it implements all methods of T.
+ var sels []*types.Selection
+ for i := 0; i < T.NumMethods(); i++ {
+ m := T.Method(i)
+ sel := msV.Lookup(m.Pkg(), m.Name())
+ if sel == nil {
+ return nil, false
+ }
+
+ f, _ := sel.Obj().(*types.Func)
+ if f == nil {
+ return nil, false
+ }
+
+ if !types.Identical(f.Type(), m.Type()) {
+ return nil, false
+ }
+
+ sels = append(sels, sel)
+ }
+ return sels, true
+}