implements.go (2501B)
1 package unused 2 3 import ( 4 "go/types" 5 6 "honnef.co/go/tools/go/types/typeutil" 7 ) 8 9 // lookupMethod returns the index of and method with matching package and name, or (-1, nil). 10 func lookupMethod(T *types.Interface, pkg *types.Package, name string) (int, *types.Func) { 11 if name != "_" { 12 for i := 0; i < T.NumMethods(); i++ { 13 m := T.Method(i) 14 if sameId(m, pkg, name) { 15 return i, m 16 } 17 } 18 } 19 return -1, nil 20 } 21 22 func sameId(obj types.Object, pkg *types.Package, name string) bool { 23 // spec: 24 // "Two identifiers are different if they are spelled differently, 25 // or if they appear in different packages and are not exported. 26 // Otherwise, they are the same." 27 if name != obj.Name() { 28 return false 29 } 30 // obj.Name == name 31 if obj.Exported() { 32 return true 33 } 34 // not exported, so packages must be the same (pkg == nil for 35 // fields in Universe scope; this can only happen for types 36 // introduced via Eval) 37 if pkg == nil || obj.Pkg() == nil { 38 return pkg == obj.Pkg() 39 } 40 // pkg != nil && obj.pkg != nil 41 return pkg.Path() == obj.Pkg().Path() 42 } 43 44 func implements(V types.Type, T *types.Interface, msV *types.MethodSet) ([]*types.Selection, bool) { 45 // fast path for common case 46 if T.Empty() { 47 return nil, true 48 } 49 50 if ityp, _ := V.Underlying().(*types.Interface); ityp != nil { 51 // TODO(dh): is this code reachable? 52 for m := range T.Methods() { 53 _, obj := lookupMethod(ityp, m.Pkg(), m.Name()) 54 switch { 55 case obj == nil: 56 return nil, false 57 case !types.Identical(obj.Type(), m.Type()): 58 return nil, false 59 } 60 } 61 return nil, true 62 } 63 64 // A concrete type implements T if it implements all methods of T. 65 var sels []*types.Selection 66 67 mapping := map[*types.TypeParam]types.Type{} 68 for m := range T.Methods() { 69 sel := msV.Lookup(m.Pkg(), m.Name()) 70 if sel == nil { 71 return nil, false 72 } 73 74 f, _ := sel.Obj().(*types.Func) 75 if f == nil { 76 return nil, false 77 } 78 79 if ok := typeutil.Unify(f.Type(), m.Type(), mapping); !ok { 80 return nil, false 81 } 82 83 sels = append(sels, sel) 84 } 85 for tparam, targ := range mapping { 86 // This checks constraints on a best-effort basis, erring on the side 87 // of accepting too many types. 88 if !satisfiesConstraint(targ, tparam) { 89 return nil, false 90 } 91 } 92 return sels, true 93 } 94 95 func satisfiesConstraint(t types.Type, tp *types.TypeParam) bool { 96 if t == nil { 97 // t is nil when we unify two type parameters. 98 return true 99 } 100 bound := tp.Constraint().Underlying().(*types.Interface) 101 return types.Satisfies(t, bound) 102 }