func processValue(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*Value, error) {
	if len(call.Args) != 1 {
		return nil, notePosition(fset.Position(call.Pos()), errors.New("call to Value takes exactly one argument"))
	}
	ok := true
	ast.Inspect(call.Args[0], func(node ast.Node) bool {
		switch expr := node.(type) {
		case nil, *ast.ArrayType, *ast.BasicLit, *ast.BinaryExpr, *ast.ChanType, *ast.CompositeLit, *ast.FuncType, *ast.Ident, *ast.IndexExpr, *ast.InterfaceType, *ast.KeyValueExpr, *ast.MapType, *ast.ParenExpr, *ast.SelectorExpr, *ast.SliceExpr, *ast.StarExpr, *ast.StructType, *ast.TypeAssertExpr:
		case *ast.UnaryExpr:
			if expr.Op == token.ARROW {
				ok = false
				return false
			}
		case *ast.CallExpr:
			if _, isFunc := info.TypeOf(expr.Fun).(*types.Signature); isFunc {
				ok = false
				return false
			}
		default:
			ok = false
			return false
		}
		return true
	})
	if !ok {
		return nil, notePosition(fset.Position(call.Pos()), errors.New("argument to Value is too complex"))
	}
	argType := info.TypeOf(call.Args[0])
	if _, isInterfaceType := argType.Underlying().(*types.Interface); isInterfaceType {
		return nil, notePosition(fset.Position(call.Pos()), fmt.Errorf("argument to Value may not be an interface value (found %s); use InterfaceValue instead", types.TypeString(argType, nil)))
	}
	return &Value{
		Pos:  call.Args[0].Pos(),
		Out:  info.TypeOf(call.Args[0]),
		expr: call.Args[0],
		info: info,
	}, nil
}
processValue creates a value from a wire.Value call.
package wire
import (
	"context"
	"errors"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"os"
	"reflect"
	"strconv"
	"strings"
	"golang.org/x/tools/go/ast/astutil"
	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/go/types/typeutil"
)
type providerSetSrc struct {
	Provider    *Provider
	Binding     *IfaceBinding
	Value       *Value
	Import      *ProviderSet
	InjectorArg *InjectorArg
	Field       *Field
}
func (p *providerSetSrc) description(fset *token.FileSet, typ types.Type) string {
	quoted := func(s string) string {
		if s == "" {
			return ""
		}
		return fmt.Sprintf("%q ", s)
	}
	switch {
	case p.Provider != nil:
		kind := "provider"
		if p.Provider.IsStruct {
			kind = "struct provider"
		}
		return fmt.Sprintf("%s %s(%s)", kind, quoted(p.Provider.Name), fset.Position(p.Provider.Pos))
	case p.Binding != nil:
		return fmt.Sprintf("wire.Bind (%s)", fset.Position(p.Binding.Pos))
	case p.Value != nil:
		return fmt.Sprintf("wire.Value (%s)", fset.Position(p.Value.Pos))
	case p.Import != nil:
		return fmt.Sprintf("provider set %s(%s)", quoted(p.Import.VarName), fset.Position(p.Import.Pos))
	case p.InjectorArg != nil:
		args := p.InjectorArg.Args
		return fmt.Sprintf("argument %s to injector function %s (%s)", args.Tuple.At(p.InjectorArg.Index).Name(), args.Name, fset.Position(args.Pos))
	case p.Field != nil:
		return fmt.Sprintf("wire.FieldsOf (%s)", fset.Position(p.Field.Pos))
	}
	panic("providerSetSrc with no fields set")
}
func (p *providerSetSrc) trace(fset *token.FileSet, typ types.Type) []string {
	var retval []string
	if p.Import != nil {
		if parent := p.Import.srcMap.At(typ); parent != nil {
			retval = append(retval, parent.(*providerSetSrc).trace(fset, typ)...)
		}
	}
	retval = append(retval, p.description(fset, typ))
	return retval
}
type ProviderSet struct {
	Pos token.Pos
	PkgPath string
	VarName string
	Providers []*Provider
	Bindings  []*IfaceBinding
	Values    []*Value
	Fields    []*Field
	Imports   []*ProviderSet
	InjectorArgs *InjectorArgs
	providerMap *typeutil.Map
	srcMap *typeutil.Map
}
func (set *ProviderSet) Outputs() []types.Type {
	return set.providerMap.Keys()
}
func (set *ProviderSet) For(t types.Type) ProvidedType {
	pt := set.providerMap.At(t)
	if pt == nil {
		return ProvidedType{}
	}
	return *pt.(*ProvidedType)
}
type IfaceBinding struct {
	Iface types.Type
	Provided types.Type
	Pos token.Pos
}
type Provider struct {
	Pkg *types.Package
	Name string
	Pos token.Pos
	Args []ProviderInput
	Varargs bool
	IsStruct bool
	Out []types.Type
	HasCleanup bool
	HasErr bool
}
type ProviderInput struct {
	Type types.Type
	FieldName string
}
type Value struct {
	Pos token.Pos
	Out types.Type
	expr ast.Expr
	info *types.Info
}
type InjectorArg struct {
	Args *InjectorArgs
	Index int
}
type InjectorArgs struct {
	Name string
	Tuple *types.Tuple
	Pos token.Pos
}
type Field struct {
	Parent types.Type
	Name string
	Pkg *types.Package
	Pos token.Pos
	Out []types.Type
}
func Load(ctx context.Context, wd string, env []string, tags string, patterns []string) (*Info, []error) {
	pkgs, errs := load(ctx, wd, env, tags, patterns)
	if len(errs) > 0 {
		return nil, errs
	}
	if len(pkgs) == 0 {
		return new(Info), nil
	}
	fset := pkgs[0].Fset
	info := &Info{
		Fset: fset,
		Sets: make(map[ProviderSetID]*ProviderSet),
	}
	oc := newObjectCache(pkgs)
	ec := new(errorCollector)
	for _, pkg := range pkgs {
		if isWireImport(pkg.PkgPath) {
			continue
		}
		scope := pkg.Types.Scope()
		for _, name := range scope.Names() {
			obj := scope.Lookup(name)
			if !isProviderSetType(obj.Type()) {
				continue
			}
			item, errs := oc.get(obj)
			if len(errs) > 0 {
				ec.add(notePositionAll(fset.Position(obj.Pos()), errs)...)
				continue
			}
			pset := item.(*ProviderSet)
			id := ProviderSetID{ImportPath: pset.PkgPath, VarName: name}
			info.Sets[id] = pset
		}
		for _, f := range pkg.Syntax {
			for _, decl := range f.Decls {
				fn, ok := decl.(*ast.FuncDecl)
				if !ok {
					continue
				}
				buildCall, err := findInjectorBuild(pkg.TypesInfo, fn)
				if err != nil {
					ec.add(notePosition(fset.Position(fn.Pos()), fmt.Errorf("inject %s: %v", fn.Name.Name, err)))
					continue
				}
				if buildCall == nil {
					continue
				}
				sig := pkg.TypesInfo.ObjectOf(fn.Name).Type().(*types.Signature)
				ins, out, err := injectorFuncSignature(sig)
				if err != nil {
					if w, ok := err.(*wireErr); ok {
						ec.add(notePosition(w.position, fmt.Errorf("inject %s: %v", fn.Name.Name, w.error)))
					} else {
						ec.add(notePosition(fset.Position(fn.Pos()), fmt.Errorf("inject %s: %v", fn.Name.Name, err)))
					}
					continue
				}
				injectorArgs := &InjectorArgs{
					Name:  fn.Name.Name,
					Tuple: ins,
					Pos:   fn.Pos(),
				}
				set, errs := oc.processNewSet(pkg.TypesInfo, pkg.PkgPath, buildCall, injectorArgs, "")
				if len(errs) > 0 {
					ec.add(notePositionAll(fset.Position(fn.Pos()), errs)...)
					continue
				}
				_, errs = solve(fset, out.out, ins, set)
				if len(errs) > 0 {
					ec.add(mapErrors(errs, func(e error) error {
						if w, ok := e.(*wireErr); ok {
							return notePosition(w.position, fmt.Errorf("inject %s: %v", fn.Name.Name, w.error))
						}
						return notePosition(fset.Position(fn.Pos()), fmt.Errorf("inject %s: %v", fn.Name.Name, e))
					})...)
					continue
				}
				info.Injectors = append(info.Injectors, &Injector{
					ImportPath: pkg.PkgPath,
					FuncName:   fn.Name.Name,
				})
			}
		}
	}
	return info, ec.errors
}
func load(ctx context.Context, wd string, env []string, tags string, patterns []string) ([]*packages.Package, []error) {
	cfg := &packages.Config{
		Context:    ctx,
		Mode:       packages.LoadAllSyntax,
		Dir:        wd,
		Env:        env,
		BuildFlags: []string{"-tags=wireinject"},
	}
	if len(tags) > 0 {
		cfg.BuildFlags[0] += " " + tags
	}
	escaped := make([]string, len(patterns))
	for i := range patterns {
		escaped[i] = "pattern=" + patterns[i]
	}
	pkgs, err := packages.Load(cfg, escaped...)
	if err != nil {
		return nil, []error{err}
	}
	var errs []error
	for _, p := range pkgs {
		for _, e := range p.Errors {
			errs = append(errs, e)
		}
	}
	if len(errs) > 0 {
		return nil, errs
	}
	return pkgs, nil
}
type Info struct {
	Fset *token.FileSet
	Sets map[ProviderSetID]*ProviderSet
	Injectors []*Injector
}
type ProviderSetID struct {
	ImportPath string
	VarName    string
}
func (id ProviderSetID) String() string {
	return strconv.Quote(id.ImportPath) + "." + id.VarName
}
type Injector struct {
	ImportPath string
	FuncName   string
}
func (in *Injector) String() string {
	return strconv.Quote(in.ImportPath) + "." + in.FuncName
}
type objectCache struct {
	fset     *token.FileSet
	packages map[string]*packages.Package
	objects  map[objRef]objCacheEntry
	hasher   typeutil.Hasher
}
type objRef struct {
	importPath string
	name       string
}
type objCacheEntry struct {
	val  interface{}  
	errs []error
}
func newObjectCache(pkgs []*packages.Package) *objectCache {
	if len(pkgs) == 0 {
		panic("object cache must have packages to draw from")
	}
	oc := &objectCache{
		fset:     pkgs[0].Fset,
		packages: make(map[string]*packages.Package),
		objects:  make(map[objRef]objCacheEntry),
		hasher:   typeutil.MakeHasher(),
	}
	stk := append([]*packages.Package(nil), pkgs...)
	for len(stk) > 0 {
		p := stk[len(stk)-1]
		stk = stk[:len(stk)-1]
		if oc.packages[p.PkgPath] != nil {
			continue
		}
		oc.packages[p.PkgPath] = p
		for _, imp := range p.Imports {
			stk = append(stk, imp)
		}
	}
	return oc
}
func (oc *objectCache) get(obj types.Object) (val interface{}, errs []error) {
	ref := objRef{
		importPath: obj.Pkg().Path(),
		name:       obj.Name(),
	}
	if ent, cached := oc.objects[ref]; cached {
		return ent.val, append([]error(nil), ent.errs...)
	}
	defer func() {
		oc.objects[ref] = objCacheEntry{
			val:  val,
			errs: append([]error(nil), errs...),
		}
	}()
	switch obj := obj.(type) {
	case *types.Var:
		spec := oc.varDecl(obj)
		if spec == nil || len(spec.Values) == 0 {
			return nil, []error{fmt.Errorf("%v is not a provider or a provider set", obj)}
		}
		var i int
		for i = range spec.Names {
			if spec.Names[i].Name == obj.Name() {
				break
			}
		}
		pkgPath := obj.Pkg().Path()
		return oc.processExpr(oc.packages[pkgPath].TypesInfo, pkgPath, spec.Values[i], obj.Name())
	case *types.Func:
		return processFuncProvider(oc.fset, obj)
	default:
		return nil, []error{fmt.Errorf("%v is not a provider or a provider set", obj)}
	}
}
func (oc *objectCache) varDecl(obj *types.Var) *ast.ValueSpec {
	pkg := oc.packages[obj.Pkg().Path()]
	pos := obj.Pos()
	for _, f := range pkg.Syntax {
		tokenFile := oc.fset.File(f.Pos())
		if base := tokenFile.Base(); base <= int(pos) && int(pos) < base+tokenFile.Size() {
			path, _ := astutil.PathEnclosingInterval(f, pos, pos)
			for _, node := range path {
				if spec, ok := node.(*ast.ValueSpec); ok {
					return spec
				}
			}
		}
	}
	return nil
}
func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Expr, varName string) (interface{}, []error) {
	exprPos := oc.fset.Position(expr.Pos())
	expr = astutil.Unparen(expr)
	if obj := qualifiedIdentObject(info, expr); obj != nil {
		item, errs := oc.get(obj)
		return item, mapErrors(errs, func(err error) error {
			return notePosition(exprPos, err)
		})
	}
	if call, ok := expr.(*ast.CallExpr); ok {
		fnObj := qualifiedIdentObject(info, call.Fun)
		if fnObj == nil {
			return nil, []error{notePosition(exprPos, errors.New("unknown pattern fnObj nil"))}
		}
		pkg := fnObj.Pkg()
		if pkg == nil {
			return nil, []error{notePosition(exprPos, fmt.Errorf("unknown pattern - pkg in fnObj is nil - %s", fnObj))}
		}
		if !isWireImport(pkg.Path()) {
			return nil, []error{notePosition(exprPos, errors.New("unknown pattern"))}
		}
		switch fnObj.Name() {
		case "NewSet":
			pset, errs := oc.processNewSet(info, pkgPath, call, nil, varName)
			return pset, notePositionAll(exprPos, errs)
		case "Bind":
			b, err := processBind(oc.fset, info, call)
			if err != nil {
				return nil, []error{notePosition(exprPos, err)}
			}
			return b, nil
		case "Value":
			v, err := processValue(oc.fset, info, call)
			if err != nil {
				return nil, []error{notePosition(exprPos, err)}
			}
			return v, nil
		case "InterfaceValue":
			v, err := processInterfaceValue(oc.fset, info, call)
			if err != nil {
				return nil, []error{notePosition(exprPos, err)}
			}
			return v, nil
		case "Struct":
			s, err := processStructProvider(oc.fset, info, call)
			if err != nil {
				return nil, []error{notePosition(exprPos, err)}
			}
			return s, nil
		case "FieldsOf":
			v, err := processFieldsOf(oc.fset, info, call)
			if err != nil {
				return nil, []error{notePosition(exprPos, err)}
			}
			return v, nil
		default:
			return nil, []error{notePosition(exprPos, errors.New("unknown pattern"))}
		}
	}
	if tn := structArgType(info, expr); tn != nil {
		p, errs := processStructLiteralProvider(oc.fset, tn)
		if len(errs) > 0 {
			return nil, notePositionAll(exprPos, errs)
		}
		return p, nil
	}
	return nil, []error{notePosition(exprPos, errors.New("unknown pattern"))}
}
func (oc *objectCache) processNewSet(info *types.Info, pkgPath string, call *ast.CallExpr, args *InjectorArgs, varName string) (*ProviderSet, []error) {
	pset := &ProviderSet{
		Pos:          call.Pos(),
		InjectorArgs: args,
		PkgPath:      pkgPath,
		VarName:      varName,
	}
	ec := new(errorCollector)
	for _, arg := range call.Args {
		item, errs := oc.processExpr(info, pkgPath, arg, "")
		if len(errs) > 0 {
			ec.add(errs...)
			continue
		}
		switch item := item.(type) {
		case *Provider:
			pset.Providers = append(pset.Providers, item)
		case *ProviderSet:
			pset.Imports = append(pset.Imports, item)
		case *IfaceBinding:
			pset.Bindings = append(pset.Bindings, item)
		case *Value:
			pset.Values = append(pset.Values, item)
		case []*Field:
			pset.Fields = append(pset.Fields, item...)
		default:
			panic("unknown item type")
		}
	}
	if len(ec.errors) > 0 {
		return nil, ec.errors
	}
	var errs []error
	pset.providerMap, pset.srcMap, errs = buildProviderMap(oc.fset, oc.hasher, pset)
	if len(errs) > 0 {
		return nil, errs
	}
	if errs := verifyAcyclic(pset.providerMap, oc.hasher); len(errs) > 0 {
		return nil, errs
	}
	return pset, nil
}
func structArgType(info *types.Info, expr ast.Expr) *types.TypeName {
	lit, ok := expr.(*ast.CompositeLit)
	if !ok {
		return nil
	}
	tn, ok := qualifiedIdentObject(info, lit.Type).(*types.TypeName)
	if !ok {
		return nil
	}
	if _, isStruct := tn.Type().Underlying().(*types.Struct); !isStruct {
		return nil
	}
	return tn
}
func qualifiedIdentObject(info *types.Info, expr ast.Expr) types.Object {
	switch expr := expr.(type) {
	case *ast.Ident:
		return info.ObjectOf(expr)
	case *ast.SelectorExpr:
		pkgName, ok := expr.X.(*ast.Ident)
		if !ok {
			return nil
		}
		if _, ok := info.ObjectOf(pkgName).(*types.PkgName); !ok {
			return nil
		}
		return info.ObjectOf(expr.Sel)
	default:
		return nil
	}
}
func processFuncProvider(fset *token.FileSet, fn *types.Func) (*Provider, []error) {
	sig := fn.Type().(*types.Signature)
	fpos := fn.Pos()
	providerSig, err := funcOutput(sig)
	if err != nil {
		return nil, []error{notePosition(fset.Position(fpos), fmt.Errorf("wrong signature for provider %s: %v", fn.Name(), err))}
	}
	params := sig.Params()
	provider := &Provider{
		Pkg:        fn.Pkg(),
		Name:       fn.Name(),
		Pos:        fn.Pos(),
		Args:       make([]ProviderInput, params.Len()),
		Varargs:    sig.Variadic(),
		Out:        []types.Type{providerSig.out},
		HasCleanup: providerSig.cleanup,
		HasErr:     providerSig.err,
	}
	for i := 0; i < params.Len(); i++ {
		provider.Args[i] = ProviderInput{
			Type: params.At(i).Type(),
		}
		for j := 0; j < i; j++ {
			if types.Identical(provider.Args[i].Type, provider.Args[j].Type) {
				return nil, []error{notePosition(fset.Position(fpos), fmt.Errorf("provider has multiple parameters of type %s", types.TypeString(provider.Args[j].Type, nil)))}
			}
		}
	}
	return provider, nil
}
func injectorFuncSignature(sig *types.Signature) (*types.Tuple, outputSignature, error) {
	out, err := funcOutput(sig)
	if err != nil {
		return nil, outputSignature{}, err
	}
	return sig.Params(), out, nil
}
type outputSignature struct {
	out     types.Type
	cleanup bool
	err     bool
}
func funcOutput(sig *types.Signature) (outputSignature, error) {
	results := sig.Results()
	switch results.Len() {
	case 0:
		return outputSignature{}, errors.New("no return values")
	case 1:
		return outputSignature{out: results.At(0).Type()}, nil
	case 2:
		out := results.At(0).Type()
		switch t := results.At(1).Type(); {
		case types.Identical(t, errorType):
			return outputSignature{out: out, err: true}, nil
		case types.Identical(t, cleanupType):
			return outputSignature{out: out, cleanup: true}, nil
		default:
			return outputSignature{}, fmt.Errorf("second return type is %s; must be error or func()", types.TypeString(t, nil))
		}
	case 3:
		if t := results.At(1).Type(); !types.Identical(t, cleanupType) {
			return outputSignature{}, fmt.Errorf("second return type is %s; must be func()", types.TypeString(t, nil))
		}
		if t := results.At(2).Type(); !types.Identical(t, errorType) {
			return outputSignature{}, fmt.Errorf("third return type is %s; must be error", types.TypeString(t, nil))
		}
		return outputSignature{
			out:     results.At(0).Type(),
			cleanup: true,
			err:     true,
		}, nil
	default:
		return outputSignature{}, errors.New("too many return values")
	}
}
func processStructLiteralProvider(fset *token.FileSet, typeName *types.TypeName) (*Provider, []error) {
	out := typeName.Type()
	st, ok := out.Underlying().(*types.Struct)
	if !ok {
		return nil, []error{fmt.Errorf("%v does not name a struct", typeName)}
	}
	pos := typeName.Pos()
	fmt.Fprintf(os.Stderr,
		"Warning: %v, see https://godoc.org/github.com/google/wire#Struct for more information.\n",
		notePosition(fset.Position(pos),
			fmt.Errorf("using struct literal to inject %s is deprecated and will be removed in the next release; use wire.Struct instead",
				typeName.Type())))
	provider := &Provider{
		Pkg:      typeName.Pkg(),
		Name:     typeName.Name(),
		Pos:      pos,
		Args:     make([]ProviderInput, st.NumFields()),
		IsStruct: true,
		Out:      []types.Type{out, types.NewPointer(out)},
	}
	for i := 0; i < st.NumFields(); i++ {
		f := st.Field(i)
		provider.Args[i] = ProviderInput{
			Type:      f.Type(),
			FieldName: f.Name(),
		}
		for j := 0; j < i; j++ {
			if types.Identical(provider.Args[i].Type, provider.Args[j].Type) {
				return nil, []error{notePosition(fset.Position(pos), fmt.Errorf("provider struct has multiple fields of type %s", types.TypeString(provider.Args[j].Type, nil)))}
			}
		}
	}
	return provider, nil
}
func processStructProvider(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*Provider, error) {
	if len(call.Args) < 1 {
		return nil, notePosition(fset.Position(call.Pos()),
			errors.New("call to Struct must specify the struct to be injected"))
	}
	const firstArgReqFormat = "first argument to Struct must be a pointer to a named struct; found %s"
	structType := info.TypeOf(call.Args[0])
	structPtr, ok := structType.(*types.Pointer)
	if !ok {
		return nil, notePosition(fset.Position(call.Pos()),
			fmt.Errorf(firstArgReqFormat, types.TypeString(structType, nil)))
	}
	st, ok := structPtr.Elem().Underlying().(*types.Struct)
	if !ok {
		return nil, notePosition(fset.Position(call.Pos()),
			fmt.Errorf(firstArgReqFormat, types.TypeString(structPtr, nil)))
	}
	stExpr := call.Args[0].(*ast.CallExpr)
	typeName := qualifiedIdentObject(info, stExpr.Args[0])  
	provider := &Provider{
		Pkg:      typeName.Pkg(),
		Name:     typeName.Name(),
		Pos:      typeName.Pos(),
		IsStruct: true,
		Out:      []types.Type{structPtr.Elem(), structPtr},
	}
	if allFields(call) {
		for i := 0; i < st.NumFields(); i++ {
			if isPrevented(st.Tag(i)) {
				continue
			}
			f := st.Field(i)
			provider.Args = append(provider.Args, ProviderInput{
				Type:      f.Type(),
				FieldName: f.Name(),
			})
		}
	} else {
		provider.Args = make([]ProviderInput, len(call.Args)-1)
		for i := 1; i < len(call.Args); i++ {
			v, err := checkField(call.Args[i], st)
			if err != nil {
				return nil, notePosition(fset.Position(call.Pos()), err)
			}
			provider.Args[i-1] = ProviderInput{
				Type:      v.Type(),
				FieldName: v.Name(),
			}
		}
	}
	for i := 0; i < len(provider.Args); i++ {
		for j := 0; j < i; j++ {
			if types.Identical(provider.Args[i].Type, provider.Args[j].Type) {
				f := st.Field(j)
				return nil, notePosition(fset.Position(f.Pos()), fmt.Errorf("provider struct has multiple fields of type %s", types.TypeString(provider.Args[j].Type, nil)))
			}
		}
	}
	return provider, nil
}
func allFields(call *ast.CallExpr) bool {
	if len(call.Args) != 2 {
		return false
	}
	b, ok := call.Args[1].(*ast.BasicLit)
	if !ok {
		return false
	}
	return strings.EqualFold(strconv.Quote("*"), b.Value)
}
func isPrevented(tag string) bool {
	return reflect.StructTag(tag).Get("wire") == "-"
}
func processBind(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*IfaceBinding, error) {
	if len(call.Args) != 2 {
		return nil, notePosition(fset.Position(call.Pos()),
			errors.New("call to Bind takes exactly two arguments"))
	}
	ifaceArgType := info.TypeOf(call.Args[0])
	ifacePtr, ok := ifaceArgType.(*types.Pointer)
	if !ok {
		return nil, notePosition(fset.Position(call.Pos()),
			fmt.Errorf("first argument to Bind must be a pointer to an interface type; found %s", types.TypeString(ifaceArgType, nil)))
	}
	iface := ifacePtr.Elem()
	methodSet, ok := iface.Underlying().(*types.Interface)
	if !ok {
		return nil, notePosition(fset.Position(call.Pos()),
			fmt.Errorf("first argument to Bind must be a pointer to an interface type; found %s", types.TypeString(ifaceArgType, nil)))
	}
	provided := info.TypeOf(call.Args[1])
	if bindShouldUsePointer(info, call) {
		providedPtr, ok := provided.(*types.Pointer)
		if !ok {
			return nil, notePosition(fset.Position(call.Args[0].Pos()),
				fmt.Errorf("second argument to Bind must be a pointer or a pointer to a pointer; found %s", types.TypeString(provided, nil)))
		}
		provided = providedPtr.Elem()
	}
	if types.Identical(iface, provided) {
		return nil, notePosition(fset.Position(call.Pos()),
			errors.New("cannot bind interface to itself"))
	}
	if !types.Implements(provided, methodSet) {
		return nil, notePosition(fset.Position(call.Pos()),
			fmt.Errorf("%s does not implement %s", types.TypeString(provided, nil), types.TypeString(iface, nil)))
	}
	return &IfaceBinding{
		Pos:      call.Pos(),
		Iface:    iface,
		Provided: provided,
	}, nil
}