func ExprType(e ast.Expr, importer Importer, fs *token.FileSet) (obj *ast.Object, typ Type) {
	ctxt := &exprTypeContext{
		importer: importer,
		fileSet:  fs,
	}
	return ctxt.exprType(e, false, "")
}
ExprType returns the type for the given expression,
and the object that represents it, if there is one.
All variables, methods, top level functions, packages, struct and
interface members, and types have objects.
The returned object can be used with DeclPos to find out
the source location of the definition of the object.
package types
import (
	"bytes"
	"container/list"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"github.com/rogpeppe/godef/go/ast"
	"github.com/rogpeppe/godef/go/parser"
	"github.com/rogpeppe/godef/go/printer"
	"github.com/rogpeppe/godef/go/scanner"
	"github.com/rogpeppe/godef/go/token"
)
type Type struct {
	Node ast.Node
	Kind ast.ObjKind
	Pkg string
	ctxt *exprTypeContext
}
type MultiValue struct {
	Types []ast.Expr
}
func (MultiValue) Pos() token.Pos {
	return token.NoPos
}
func (MultiValue) End() token.Pos {
	return token.NoPos
}
var badType = Type{Kind: ast.Bad}
var makeIdent = predecl("make")
var newIdent = predecl("new")
var falseIdent = predecl("false")
var trueIdent = predecl("true")
var iotaIdent = predecl("iota")
var boolIdent = predecl("bool")
var intIdent = predecl("int")
var floatIdent = predecl("float")
var stringIdent = predecl("string")
func predecl(name string) *ast.Ident {
	return &ast.Ident{Name: name, Obj: parser.Universe.Lookup(name)}
}
type Importer func(path string, srcDir string) *ast.Package
var FileSet = token.NewFileSet()
func DefaultImporter(path string, srcDir string) *ast.Package {
	bpkg, err := build.Default.Import(path, srcDir, 0)
	if err != nil {
		return nil
	}
	goFiles := make(map[string]bool)
	for _, f := range bpkg.GoFiles {
		goFiles[f] = true
	}
	for _, f := range bpkg.CgoFiles {
		goFiles[f] = true
	}
	shouldInclude := func(d os.FileInfo) bool {
		return goFiles[d.Name()]
	}
	pkgs, err := parser.ParseDir(FileSet, bpkg.Dir, shouldInclude, 0, DefaultImportPathToName)
	if err != nil {
		if Debug {
			switch err := err.(type) {
			case scanner.ErrorList:
				for _, e := range err {
					debugp("\t%v: %s", e.Pos, e.Msg)
				}
			default:
				debugp("\terror parsing %s: %v", bpkg.Dir, err)
			}
		}
		return nil
	}
	if pkg := pkgs[bpkg.Name]; pkg != nil {
		return pkg
	}
	if Debug {
		debugp("package not found by ParseDir!")
	}
	return nil
}
func DefaultImportPathToName(path, srcDir string) (string, error) {
	if path == "C" {
		return "C", nil
	}
	pkg, err := build.Default.Import(path, srcDir, 0)
	return pkg.Name, err
}
func isGoFile(d os.FileInfo) bool {
	return strings.HasSuffix(d.Name(), ".go") &&
		!strings.HasSuffix(d.Name(), "_test.go") &&
		!strings.HasPrefix(d.Name(), ".") &&
		goodOSArch(d.Name())
}
var Debug = false
func (t Type) String() string {
	return fmt.Sprintf("Type{%v %q %T %v}", t.Kind, t.Pkg, t.Node, pretty{t.Node})
}
var Panic = true
func (t Type) Member(name string) *ast.Object {
	debugp("member %v '%s' {", t, name)
	if t.Pkg != "" && !ast.IsExported(name) {
		return nil
	}
	c := make(chan *ast.Object)
	go func() {
		if !Panic {
			defer func() {
				if err := recover(); err != nil {
					log.Printf("panic: %v", err)
					c <- nil
				}
			}()
		}
		doMembers(t, name, func(obj *ast.Object) {
			if obj.Name == name {
				c <- obj
				runtime.Goexit()
			}
		})
		c <- nil
	}()
	m := <-c
	debugp("} -> %v", m)
	return m
}
func (t Type) Iter() <-chan *ast.Object {
	c := make(chan *ast.Object)
	go func() {
		internal := t.Pkg == ""
		doMembers(t, "", func(obj *ast.Object) {
			if internal || ast.IsExported(obj.Name) {
				c <- obj
			}
		})
		close(c)
	}()
	return c
}