func ensurePointer(T types.Type) types.Type {
	if _, ok := T.(*types.Named); ok && !IsInterface(T) {
		return types.NewPointer(T)
	}
	return T
}
ensurePointer wraps T in a *types.Pointer if T is a named, non-interface
type. This is useful to make sure you consider a named type's full method
set.
package source
import (
	"context"
	"errors"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"sort"
	"github.com/govim/govim/cmd/govim/internal/golang_org_x_tools/event"
	"github.com/govim/govim/cmd/govim/internal/golang_org_x_tools/lsp/protocol"
	"github.com/govim/govim/cmd/govim/internal/golang_org_x_tools/span"
	"golang.org/x/xerrors"
)
func Implementation(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position) ([]protocol.Location, error) {
	ctx, done := event.Start(ctx, "source.Implementation")
	defer done()
	impls, err := implementations(ctx, snapshot, f, pp)
	if err != nil {
		return nil, err
	}
	var locations []protocol.Location
	for _, impl := range impls {
		if impl.pkg == nil || len(impl.pkg.CompiledGoFiles()) == 0 {
			continue
		}
		rng, err := objToMappedRange(snapshot, impl.pkg, impl.obj)
		if err != nil {
			return nil, err
		}
		pr, err := rng.Range()
		if err != nil {
			return nil, err
		}
		locations = append(locations, protocol.Location{
			URI:   protocol.URIFromSpanURI(rng.URI()),
			Range: pr,
		})
	}
	sort.Slice(locations, func(i, j int) bool {
		li, lj := locations[i], locations[j]
		if li.URI == lj.URI {
			return protocol.CompareRange(li.Range, lj.Range) < 0
		}
		return li.URI < lj.URI
	})
	return locations, nil
}
var ErrNotAType = errors.New("not a type name or method")
func implementations(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position) ([]qualifiedObject, error) {
	var (
		impls []qualifiedObject
		seen  = make(map[token.Position]bool)
		fset  = s.FileSet()
	)
	qos, err := qualifiedObjsAtProtocolPos(ctx, s, f.URI(), pp)
	if err != nil {
		return nil, err
	}
	for _, qo := range qos {
		var (
			queryType   types.Type
			queryMethod *types.Func
		)
		switch obj := qo.obj.(type) {
		case *types.Func:
			queryMethod = obj
			if recv := obj.Type().(*types.Signature).Recv(); recv != nil {
				queryType = ensurePointer(recv.Type())
			}
		case *types.TypeName:
			queryType = ensurePointer(obj.Type())
		}
		if queryType == nil {
			return nil, ErrNotAType
		}
		if types.NewMethodSet(queryType).Len() == 0 {
			return nil, nil
		}
		var (
			allNamed []*types.Named
			pkgs     = make(map[*types.Package]Package)
		)
		knownPkgs, err := s.KnownPackages(ctx)
		if err != nil {
			return nil, err
		}
		for _, pkg := range knownPkgs {
			pkgs[pkg.GetTypes()] = pkg
			info := pkg.GetTypesInfo()
			for _, obj := range info.Defs {
				obj, ok := obj.(*types.TypeName)
				if !ok || obj.IsAlias() {
					continue
				}
				if named, ok := obj.Type().(*types.Named); ok {
					allNamed = append(allNamed, named)
				}
			}
		}
		for _, named := range allNamed {
			var (
				candObj  types.Object = named.Obj()
				candType              = ensurePointer(named)
			)
			if !concreteImplementsIntf(candType, queryType) {
				continue
			}
			ms := types.NewMethodSet(candType)
			if ms.Len() == 0 {
				continue
			}
			if queryMethod != nil {
				sel := ms.Lookup(queryMethod.Pkg(), queryMethod.Name())
				if sel == nil {
					continue
				}
				candObj = sel.Obj()
			}
			pos := fset.Position(candObj.Pos())
			if candObj == queryMethod || seen[pos] {
				continue
			}
			seen[pos] = true
			impls = append(impls, qualifiedObject{
				obj: candObj,
				pkg: pkgs[candObj.Pkg()],
			})
		}
	}
	return impls, nil
}
func concreteImplementsIntf(a, b types.Type) bool {
	aIsIntf, bIsIntf := IsInterface(a), IsInterface(b)
	if aIsIntf == bIsIntf {
		return false
	}
	if aIsIntf {
		a, b = b, a
	}
	return types.AssignableTo(a, b)
}