func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, assign map[string][]interface{}) {
	typeof = make(map[interface{}]string)
	assign = make(map[string][]interface{})
	cfg1 := &TypeConfig{}
	*cfg1 = *cfg // make copy so we can add locally
	copied := false

	// gather function declarations
	for _, decl := range f.Decls {
		fn, ok := decl.(*ast.FuncDecl)
		if !ok {
			continue
		}
		typecheck1(cfg, fn.Type, typeof, assign)
		t := typeof[fn.Type]
		if fn.Recv != nil {
			// The receiver must be a type.
			rcvr := typeof[fn.Recv]
			if !isType(rcvr) {
				if len(fn.Recv.List) != 1 {
					continue
				}
				rcvr = mkType(gofmt(fn.Recv.List[0].Type))
				typeof[fn.Recv.List[0].Type] = rcvr
			}
			rcvr = getType(rcvr)
			if rcvr != "" && rcvr[0] == '*' {
				rcvr = rcvr[1:]
			}
			typeof[rcvr+"."+fn.Name.Name] = t
		} else {
			if isType(t) {
				t = getType(t)
			} else {
				t = gofmt(fn.Type)
			}
			typeof[fn.Name] = t

			// Record typeof[fn.Name.Obj] for future references to fn.Name.
			typeof[fn.Name.Obj] = t
		}
	}

	// gather struct declarations
	for _, decl := range f.Decls {
		d, ok := decl.(*ast.GenDecl)
		if ok {
			for _, s := range d.Specs {
				switch s := s.(type) {
				case *ast.TypeSpec:
					if cfg1.Type[s.Name.Name] != nil {
						break
					}
					if !copied {
						copied = true
						// Copy map lazily: it's time.
						cfg1.Type = make(map[string]*Type)
						for k, v := range cfg.Type {
							cfg1.Type[k] = v
						}
					}
					t := &Type{Field: map[string]string{}}
					cfg1.Type[s.Name.Name] = t
					switch st := s.Type.(type) {
					case *ast.StructType:
						for _, f := range st.Fields.List {
							for _, n := range f.Names {
								t.Field[n.Name] = gofmt(f.Type)
							}
						}
					case *ast.ArrayType, *ast.StarExpr, *ast.MapType:
						t.Def = gofmt(st)
					}
				}
			}
		}
	}

	typecheck1(cfg1, f, typeof, assign)
	return typeof, assign
}
func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, assign map[string][]interface{}) {
	typeof = make(map[interface{}]string)
	assign = make(map[string][]interface{})
	cfg1 := &TypeConfig{}
	*cfg1 = *cfg 
	copied := false

	
	for _, decl := range f.Decls {
		fn, ok := decl.(*ast.FuncDecl)
		if !ok {
			continue
		}
		typecheck1(cfg, fn.Type, typeof, assign)
		t := typeof[fn.Type]
		if fn.Recv != nil {
			
			rcvr := typeof[fn.Recv]
			if !isType(rcvr) {
				if len(fn.Recv.List) != 1 {
					continue
				}
				rcvr = mkType(gofmt(fn.Recv.List[0].Type))
				typeof[fn.Recv.List[0].Type] = rcvr
			}
			rcvr = getType(rcvr)
			if rcvr != "" && rcvr[0] == '*' {
				rcvr = rcvr[1:]
			}
			typeof[rcvr+"."+fn.Name.Name] = t
		} else {
			if isType(t) {
				t = getType(t)
			} else {
				t = gofmt(fn.Type)
			}
			typeof[fn.Name] = t

			
			typeof[fn.Name.Obj] = t
		}
	}

	
	for _, decl := range f.Decls {
		d, ok := decl.(*ast.GenDecl)
		if ok {
			for _, s := range d.Specs {
				switch s := s.(type) {
				case *ast.TypeSpec:
					if cfg1.Type[s.Name.Name] != nil {
						break
					}
					if !copied {
						copied = true
						
						cfg1.Type = make(map[string]*Type)
						for k, v := range cfg.Type {
							cfg1.Type[k] = v
						}
					}
					t := &Type{Field: map[string]string{}}
					cfg1.Type[s.Name.Name] = t
					switch st := s.Type.(type) {
					case *ast.StructType:
						for _, f := range st.Fields.List {
							for _, n := range f.Names {
								t.Field[n.Name] = gofmt(f.Type)
							}
						}
					case *ast.ArrayType, *ast.StarExpr, *ast.MapType:
						t.Def = gofmt(st)
					}
				}
			}
		}
	}

	typecheck1(cfg1, f, typeof, assign)
	return typeof, assign
}
func typecheck ( cfg * TypeConfig , f * ast . File ) ( typeof map [ interface { } ] string , assign map [ string ] [ ] interface { } ) { typeof = make ( map [ interface { } ] string ) assign = make ( map [ string ] [ ] interface { } ) cfg1 := & TypeConfig { } * cfg1 = * cfg // make copy so we can add locally copied := false // gather function declarations for _ , decl := range f . Decls { fn , ok := decl . ( * ast . FuncDecl ) if ! ok { continue } typecheck1 ( cfg , fn . Type , typeof , assign ) t := typeof [ fn . Type ] if fn . Recv != nil { // The receiver must be a type. rcvr := typeof [ fn . Recv ] if ! isType ( rcvr ) { if len ( fn . Recv . List ) != 1 { continue } rcvr = mkType ( gofmt ( fn . Recv . List [ 0 ] . Type ) ) typeof [ fn . Recv . List [ 0 ] . Type ] = rcvr } rcvr = getType ( rcvr ) if rcvr != " " && rcvr [ 0 ] == '*' { rcvr = rcvr [ 1 : ] } typeof [ rcvr + " " + fn . Name . Name ] = t } else { if isType ( t ) { t = getType ( t ) } else { t = gofmt ( fn . Type ) } typeof [ fn . Name ] = t // Record typeof[fn.Name.Obj] for future references to fn.Name. typeof [ fn . Name . Obj ] = t } } // gather struct declarations for _ , decl := range f . Decls { d , ok := decl . ( * ast . GenDecl ) if ok { for _ , s := range d . Specs { switch s := s . ( type ) { case * ast . TypeSpec : if cfg1 . Type [ s . Name . Name ] != nil { break } if ! copied { copied = true // Copy map lazily: it's time. cfg1 . Type = make ( map [ string ] * Type ) for k , v := range cfg . Type { cfg1 . Type [ k ] = v } } t := & Type { Field : map [ string ] string { } } cfg1 . Type [ s . Name . Name ] = t switch st := s . Type . ( type ) { case * ast . StructType : for _ , f := range st . Fields . List { for _ , n := range f . Names { t . Field [ n . Name ] = gofmt ( f . Type ) } } case * ast . ArrayType , * ast . StarExpr , * ast . MapType : t . Def = gofmt ( st ) } } } } } typecheck1 ( cfg1 , f , typeof , assign ) return typeof , assign }
// typecheck type checks the AST f assuming the information in cfg.
// It returns two maps with type information:
// typeof maps AST nodes to type information in gofmt string form.
// assign maps type strings to lists of expressions that were assigned
// to values of another type that were assigned to that type.
typecheck type checks the AST f assuming the information in cfg . It returns two maps with type information : typeof maps AST nodes to type information in gofmt string form . assign maps type strings to lists of expressions that were assigned to values of another type that were assigned to that type .