src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }