import (
        "bufio"
        "cmd/compile/internal/base"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/obj/x86"
        types.TypeLinkSym = func(t *types.Type) *obj.LSym {
                return typenamesym(t).Linksym()
        }
-       TypecheckInit()
+       typecheck.Init()
        os.Exit(m.Run())
 }
 
 
 
 import (
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
        "fmt"
 
 func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
        field := types.NewField(src.NoXPos, s, t)
-       n := NewName(s)
+       n := typecheck.NewName(s)
        n.Class_ = which
        field.Nname = n
        n.SetType(t)
 }
 
 func mkFuncType(rcvr *types.Type, ins []*types.Type, outs []*types.Type) *types.Type {
-       q := lookup("?")
+       q := typecheck.Lookup("?")
        inf := []*types.Field{}
        for _, it := range ins {
                inf = append(inf, mkParamResultField(it, q, ir.PPARAM))
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "fmt"
                        return closure
                }
                if memhashvarlen == nil {
-                       memhashvarlen = sysfunc("memhash_varlen")
+                       memhashvarlen = typecheck.LookupRuntimeFunc("memhash_varlen")
                }
                ot := 0
                ot = dsymptr(closure, ot, memhashvarlen, 0)
        }
 
        base.Pos = base.AutogeneratedPos // less confusing than end of input
-       dclcontext = ir.PEXTERN
+       typecheck.DeclContext = ir.PEXTERN
 
        // func sym(p *T, h uintptr) uintptr
        args := []*ir.Field{
-               ir.NewField(base.Pos, lookup("p"), nil, types.NewPtr(t)),
-               ir.NewField(base.Pos, lookup("h"), nil, types.Types[types.TUINTPTR]),
+               ir.NewField(base.Pos, typecheck.Lookup("p"), nil, types.NewPtr(t)),
+               ir.NewField(base.Pos, typecheck.Lookup("h"), nil, types.Types[types.TUINTPTR]),
        }
        results := []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR])}
        tfn := ir.NewFuncType(base.Pos, nil, args, results)
 
-       fn := dclfunc(sym, tfn)
+       fn := typecheck.DeclFunc(sym, tfn)
        np := ir.AsNode(tfn.Type().Params().Field(0).Nname)
        nh := ir.AsNode(tfn.Type().Params().Field(1).Nname)
 
                hashel := hashfor(t.Elem())
 
                // for i := 0; i < nelem; i++
-               ni := temp(types.Types[types.TINT])
+               ni := typecheck.Temp(types.Types[types.TINT])
                init := ir.NewAssignStmt(base.Pos, ni, ir.NewInt(0))
                cond := ir.NewBinaryExpr(base.Pos, ir.OLT, ni, ir.NewInt(t.NumElem()))
                post := ir.NewAssignStmt(base.Pos, ni, ir.NewBinaryExpr(base.Pos, ir.OADD, ni, ir.NewInt(1)))
 
                nx := ir.NewIndexExpr(base.Pos, np, ni)
                nx.SetBounded(true)
-               na := nodAddr(nx)
+               na := typecheck.NodAddr(nx)
                call.Args.Append(na)
                call.Args.Append(nh)
                loop.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
                                hashel := hashfor(f.Type)
                                call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
                                nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
-                               na := nodAddr(nx)
+                               na := typecheck.NodAddr(nx)
                                call.Args.Append(na)
                                call.Args.Append(nh)
                                fn.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
                        hashel := hashmem(f.Type)
                        call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
                        nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
-                       na := nodAddr(nx)
+                       na := typecheck.NodAddr(nx)
                        call.Args.Append(na)
                        call.Args.Append(nh)
                        call.Args.Append(ir.NewInt(size))
                ir.DumpList("genhash body", fn.Body)
        }
 
-       funcbody()
+       typecheck.FinishFuncBody()
 
        fn.SetDupok(true)
-       typecheckFunc(fn)
+       typecheck.Func(fn)
 
        ir.CurFunc = fn
-       typecheckslice(fn.Body, ctxStmt)
+       typecheck.Stmts(fn.Body)
        ir.CurFunc = nil
 
        if base.Debug.DclStack != 0 {
        }
 
        fn.SetNilCheckDisabled(true)
-       Target.Decls = append(Target.Decls, fn)
+       typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
 
        // Build closure. It doesn't close over any variables, so
        // it contains just the function pointer.
                sym = typesymprefix(".hash", t)
        }
 
-       n := NewName(sym)
+       n := typecheck.NewName(sym)
        ir.MarkFunc(n)
-       n.SetType(functype(nil, []*ir.Field{
+       n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
                ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
                ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
        }, []*ir.Field{
 // sysClosure returns a closure which will call the
 // given runtime function (with no closed-over variables).
 func sysClosure(name string) *obj.LSym {
-       s := sysvar(name + "·f")
+       s := typecheck.LookupRuntimeVar(name + "·f")
        if len(s.P) == 0 {
-               f := sysfunc(name)
+               f := typecheck.LookupRuntimeFunc(name)
                dsymptr(s, 0, f, 0)
                ggloblsym(s, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
        }
                        return closure
                }
                if memequalvarlen == nil {
-                       memequalvarlen = sysvar("memequal_varlen") // asm func
+                       memequalvarlen = typecheck.LookupRuntimeVar("memequal_varlen") // asm func
                }
                ot := 0
                ot = dsymptr(closure, ot, memequalvarlen, 0)
        // Autogenerate code for equality of structs and arrays.
 
        base.Pos = base.AutogeneratedPos // less confusing than end of input
-       dclcontext = ir.PEXTERN
+       typecheck.DeclContext = ir.PEXTERN
 
        // func sym(p, q *T) bool
        tfn := ir.NewFuncType(base.Pos, nil,
-               []*ir.Field{ir.NewField(base.Pos, lookup("p"), nil, types.NewPtr(t)), ir.NewField(base.Pos, lookup("q"), nil, types.NewPtr(t))},
-               []*ir.Field{ir.NewField(base.Pos, lookup("r"), nil, types.Types[types.TBOOL])})
+               []*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("p"), nil, types.NewPtr(t)), ir.NewField(base.Pos, typecheck.Lookup("q"), nil, types.NewPtr(t))},
+               []*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("r"), nil, types.Types[types.TBOOL])})
 
-       fn := dclfunc(sym, tfn)
+       fn := typecheck.DeclFunc(sym, tfn)
        np := ir.AsNode(tfn.Type().Params().Field(0).Nname)
        nq := ir.AsNode(tfn.Type().Params().Field(1).Nname)
        nr := ir.AsNode(tfn.Type().Results().Field(0).Nname)
 
        // Label to jump to if an equality test fails.
-       neq := autolabel(".neq")
+       neq := typecheck.AutoLabel(".neq")
 
        // We reach here only for types that have equality but
        // cannot be handled by the standard algorithms,
                        } else {
                                // Generate a for loop.
                                // for i := 0; i < nelem; i++
-                               i := temp(types.Types[types.TINT])
+                               i := typecheck.Temp(types.Types[types.TINT])
                                init := ir.NewAssignStmt(base.Pos, i, ir.NewInt(0))
                                cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(nelem))
                                post := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(1)))
 
        // ret:
        //   return
-       ret := autolabel(".ret")
+       ret := typecheck.AutoLabel(".ret")
        fn.Body.Append(ir.NewLabelStmt(base.Pos, ret))
        fn.Body.Append(ir.NewReturnStmt(base.Pos, nil))
 
                ir.DumpList("geneq body", fn.Body)
        }
 
-       funcbody()
+       typecheck.FinishFuncBody()
 
        fn.SetDupok(true)
-       typecheckFunc(fn)
+       typecheck.Func(fn)
 
        ir.CurFunc = fn
-       typecheckslice(fn.Body, ctxStmt)
+       typecheck.Stmts(fn.Body)
        ir.CurFunc = nil
 
        if base.Debug.DclStack != 0 {
        // neither of which can be nil, and our comparisons
        // are shallow.
        fn.SetNilCheckDisabled(true)
-       Target.Decls = append(Target.Decls, fn)
+       typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
 
        // Generate a closure which points at the function we just generated.
        dsymptr(closure, 0, sym.Linksym(), 0)
 // which can be used to construct string equality comparison.
 // eqlen must be evaluated before eqmem, and shortcircuiting is required.
 func eqstring(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
-       s = conv(s, types.Types[types.TSTRING])
-       t = conv(t, types.Types[types.TSTRING])
+       s = typecheck.Conv(s, types.Types[types.TSTRING])
+       t = typecheck.Conv(t, types.Types[types.TSTRING])
        sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
        tptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, t)
-       slen := conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, s), types.Types[types.TUINTPTR])
-       tlen := conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, t), types.Types[types.TUINTPTR])
+       slen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, s), types.Types[types.TUINTPTR])
+       tlen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, t), types.Types[types.TUINTPTR])
 
-       fn := syslook("memequal")
-       fn = substArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
+       fn := typecheck.LookupRuntime("memequal")
+       fn = typecheck.SubstArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
        call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, []ir.Node{sptr, tptr, ir.Copy(slen)})
-       TypecheckCall(call)
+       typecheck.Call(call)
 
        cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen)
-       cmp = typecheck(cmp, ctxExpr).(*ir.BinaryExpr)
+       cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
        cmp.SetType(types.Types[types.TBOOL])
        return cmp, call
 }
        // func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
        var fn ir.Node
        if s.Type().IsEmptyInterface() {
-               fn = syslook("efaceeq")
+               fn = typecheck.LookupRuntime("efaceeq")
        } else {
-               fn = syslook("ifaceeq")
+               fn = typecheck.LookupRuntime("ifaceeq")
        }
 
        stab := ir.NewUnaryExpr(base.Pos, ir.OITAB, s)
        tdata.SetTypecheck(1)
 
        call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, []ir.Node{stab, sdata, tdata})
-       TypecheckCall(call)
+       typecheck.Call(call)
 
        cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, stab, ttab)
-       cmp = typecheck(cmp, ctxExpr).(*ir.BinaryExpr)
+       cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
        cmp.SetType(types.Types[types.TBOOL])
        return cmp, call
 }
 // eqmem returns the node
 //     memequal(&p.field, &q.field [, size])
 func eqmem(p ir.Node, q ir.Node, field *types.Sym, size int64) ir.Node {
-       nx := typecheck(nodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)), ctxExpr)
-       ny := typecheck(nodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)), ctxExpr)
+       nx := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)))
+       ny := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)))
 
        fn, needsize := eqmemfunc(size, nx.Type().Elem())
        call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
 func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
        switch size {
        default:
-               fn = syslook("memequal")
+               fn = typecheck.LookupRuntime("memequal")
                needsize = true
        case 1, 2, 4, 8, 16:
                buf := fmt.Sprintf("memequal%d", int(size)*8)
-               fn = syslook(buf)
+               fn = typecheck.LookupRuntime(buf)
        }
 
-       fn = substArgTypes(fn, t, t)
+       fn = typecheck.SubstArgTypes(fn, t, t)
        return fn, needsize
 }
 
 
+++ /dev/null
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-)
-
-type exporter struct {
-       marked map[*types.Type]bool // types already seen by markType
-}
-
-// markObject visits a reachable object.
-func (p *exporter) markObject(n ir.Node) {
-       if n.Op() == ir.ONAME {
-               n := n.(*ir.Name)
-               if n.Class_ == ir.PFUNC {
-                       inlFlood(n, exportsym)
-               }
-       }
-
-       p.markType(n.Type())
-}
-
-// markType recursively visits types reachable from t to identify
-// functions whose inline bodies may be needed.
-func (p *exporter) markType(t *types.Type) {
-       if p.marked[t] {
-               return
-       }
-       p.marked[t] = true
-
-       // If this is a named type, mark all of its associated
-       // methods. Skip interface types because t.Methods contains
-       // only their unexpanded method set (i.e., exclusive of
-       // interface embeddings), and the switch statement below
-       // handles their full method set.
-       if t.Sym() != nil && t.Kind() != types.TINTER {
-               for _, m := range t.Methods().Slice() {
-                       if types.IsExported(m.Sym.Name) {
-                               p.markObject(ir.AsNode(m.Nname))
-                       }
-               }
-       }
-
-       // Recursively mark any types that can be produced given a
-       // value of type t: dereferencing a pointer; indexing or
-       // iterating over an array, slice, or map; receiving from a
-       // channel; accessing a struct field or interface method; or
-       // calling a function.
-       //
-       // Notably, we don't mark function parameter types, because
-       // the user already needs some way to construct values of
-       // those types.
-       switch t.Kind() {
-       case types.TPTR, types.TARRAY, types.TSLICE:
-               p.markType(t.Elem())
-
-       case types.TCHAN:
-               if t.ChanDir().CanRecv() {
-                       p.markType(t.Elem())
-               }
-
-       case types.TMAP:
-               p.markType(t.Key())
-               p.markType(t.Elem())
-
-       case types.TSTRUCT:
-               for _, f := range t.FieldSlice() {
-                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
-                               p.markType(f.Type)
-                       }
-               }
-
-       case types.TFUNC:
-               for _, f := range t.Results().FieldSlice() {
-                       p.markType(f.Type)
-               }
-
-       case types.TINTER:
-               for _, f := range t.FieldSlice() {
-                       if types.IsExported(f.Sym.Name) {
-                               p.markType(f.Type)
-                       }
-               }
-       }
-}
-
-// ----------------------------------------------------------------------------
-// Export format
-
-// Tags. Must be < 0.
-const (
-       // Objects
-       packageTag = -(iota + 1)
-       constTag
-       typeTag
-       varTag
-       funcTag
-       endTag
-
-       // Types
-       namedTag
-       arrayTag
-       sliceTag
-       dddTag
-       structTag
-       pointerTag
-       signatureTag
-       interfaceTag
-       mapTag
-       chanTag
-
-       // Values
-       falseTag
-       trueTag
-       int64Tag
-       floatTag
-       fractionTag // not used by gc
-       complexTag
-       stringTag
-       nilTag
-       unknownTag // not used by gc (only appears in packages with errors)
-
-       // Type aliases
-       aliasTag
-)
-
-var predecl []*types.Type // initialized lazily
-
-func predeclared() []*types.Type {
-       if predecl == nil {
-               // initialize lazily to be sure that all
-               // elements have been initialized before
-               predecl = []*types.Type{
-                       // basic types
-                       types.Types[types.TBOOL],
-                       types.Types[types.TINT],
-                       types.Types[types.TINT8],
-                       types.Types[types.TINT16],
-                       types.Types[types.TINT32],
-                       types.Types[types.TINT64],
-                       types.Types[types.TUINT],
-                       types.Types[types.TUINT8],
-                       types.Types[types.TUINT16],
-                       types.Types[types.TUINT32],
-                       types.Types[types.TUINT64],
-                       types.Types[types.TUINTPTR],
-                       types.Types[types.TFLOAT32],
-                       types.Types[types.TFLOAT64],
-                       types.Types[types.TCOMPLEX64],
-                       types.Types[types.TCOMPLEX128],
-                       types.Types[types.TSTRING],
-
-                       // basic type aliases
-                       types.ByteType,
-                       types.RuneType,
-
-                       // error
-                       types.ErrorType,
-
-                       // untyped types
-                       types.UntypedBool,
-                       types.UntypedInt,
-                       types.UntypedRune,
-                       types.UntypedFloat,
-                       types.UntypedComplex,
-                       types.UntypedString,
-                       types.Types[types.TNIL],
-
-                       // package unsafe
-                       types.Types[types.TUNSAFEPTR],
-
-                       // invalid type (package contains errors)
-                       types.Types[types.Txxx],
-
-                       // any type, for builtin export data
-                       types.Types[types.TANY],
-               }
-       }
-       return predecl
-}
 
+++ /dev/null
-// Code generated by mkbuiltin.go. DO NOT EDIT.
-
-package gc
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-)
-
-var runtimeDecls = [...]struct {
-       name string
-       tag  int
-       typ  int
-}{
-       {"newobject", funcTag, 4},
-       {"mallocgc", funcTag, 8},
-       {"panicdivide", funcTag, 9},
-       {"panicshift", funcTag, 9},
-       {"panicmakeslicelen", funcTag, 9},
-       {"panicmakeslicecap", funcTag, 9},
-       {"throwinit", funcTag, 9},
-       {"panicwrap", funcTag, 9},
-       {"gopanic", funcTag, 11},
-       {"gorecover", funcTag, 14},
-       {"goschedguarded", funcTag, 9},
-       {"goPanicIndex", funcTag, 16},
-       {"goPanicIndexU", funcTag, 18},
-       {"goPanicSliceAlen", funcTag, 16},
-       {"goPanicSliceAlenU", funcTag, 18},
-       {"goPanicSliceAcap", funcTag, 16},
-       {"goPanicSliceAcapU", funcTag, 18},
-       {"goPanicSliceB", funcTag, 16},
-       {"goPanicSliceBU", funcTag, 18},
-       {"goPanicSlice3Alen", funcTag, 16},
-       {"goPanicSlice3AlenU", funcTag, 18},
-       {"goPanicSlice3Acap", funcTag, 16},
-       {"goPanicSlice3AcapU", funcTag, 18},
-       {"goPanicSlice3B", funcTag, 16},
-       {"goPanicSlice3BU", funcTag, 18},
-       {"goPanicSlice3C", funcTag, 16},
-       {"goPanicSlice3CU", funcTag, 18},
-       {"printbool", funcTag, 19},
-       {"printfloat", funcTag, 21},
-       {"printint", funcTag, 23},
-       {"printhex", funcTag, 25},
-       {"printuint", funcTag, 25},
-       {"printcomplex", funcTag, 27},
-       {"printstring", funcTag, 29},
-       {"printpointer", funcTag, 30},
-       {"printuintptr", funcTag, 31},
-       {"printiface", funcTag, 30},
-       {"printeface", funcTag, 30},
-       {"printslice", funcTag, 30},
-       {"printnl", funcTag, 9},
-       {"printsp", funcTag, 9},
-       {"printlock", funcTag, 9},
-       {"printunlock", funcTag, 9},
-       {"concatstring2", funcTag, 34},
-       {"concatstring3", funcTag, 35},
-       {"concatstring4", funcTag, 36},
-       {"concatstring5", funcTag, 37},
-       {"concatstrings", funcTag, 39},
-       {"cmpstring", funcTag, 40},
-       {"intstring", funcTag, 43},
-       {"slicebytetostring", funcTag, 44},
-       {"slicebytetostringtmp", funcTag, 45},
-       {"slicerunetostring", funcTag, 48},
-       {"stringtoslicebyte", funcTag, 50},
-       {"stringtoslicerune", funcTag, 53},
-       {"slicecopy", funcTag, 54},
-       {"decoderune", funcTag, 55},
-       {"countrunes", funcTag, 56},
-       {"convI2I", funcTag, 57},
-       {"convT16", funcTag, 58},
-       {"convT32", funcTag, 58},
-       {"convT64", funcTag, 58},
-       {"convTstring", funcTag, 58},
-       {"convTslice", funcTag, 58},
-       {"convT2E", funcTag, 59},
-       {"convT2Enoptr", funcTag, 59},
-       {"convT2I", funcTag, 59},
-       {"convT2Inoptr", funcTag, 59},
-       {"assertE2I", funcTag, 57},
-       {"assertE2I2", funcTag, 60},
-       {"assertI2I", funcTag, 57},
-       {"assertI2I2", funcTag, 60},
-       {"panicdottypeE", funcTag, 61},
-       {"panicdottypeI", funcTag, 61},
-       {"panicnildottype", funcTag, 62},
-       {"ifaceeq", funcTag, 64},
-       {"efaceeq", funcTag, 64},
-       {"fastrand", funcTag, 66},
-       {"makemap64", funcTag, 68},
-       {"makemap", funcTag, 69},
-       {"makemap_small", funcTag, 70},
-       {"mapaccess1", funcTag, 71},
-       {"mapaccess1_fast32", funcTag, 72},
-       {"mapaccess1_fast64", funcTag, 72},
-       {"mapaccess1_faststr", funcTag, 72},
-       {"mapaccess1_fat", funcTag, 73},
-       {"mapaccess2", funcTag, 74},
-       {"mapaccess2_fast32", funcTag, 75},
-       {"mapaccess2_fast64", funcTag, 75},
-       {"mapaccess2_faststr", funcTag, 75},
-       {"mapaccess2_fat", funcTag, 76},
-       {"mapassign", funcTag, 71},
-       {"mapassign_fast32", funcTag, 72},
-       {"mapassign_fast32ptr", funcTag, 72},
-       {"mapassign_fast64", funcTag, 72},
-       {"mapassign_fast64ptr", funcTag, 72},
-       {"mapassign_faststr", funcTag, 72},
-       {"mapiterinit", funcTag, 77},
-       {"mapdelete", funcTag, 77},
-       {"mapdelete_fast32", funcTag, 78},
-       {"mapdelete_fast64", funcTag, 78},
-       {"mapdelete_faststr", funcTag, 78},
-       {"mapiternext", funcTag, 79},
-       {"mapclear", funcTag, 80},
-       {"makechan64", funcTag, 82},
-       {"makechan", funcTag, 83},
-       {"chanrecv1", funcTag, 85},
-       {"chanrecv2", funcTag, 86},
-       {"chansend1", funcTag, 88},
-       {"closechan", funcTag, 30},
-       {"writeBarrier", varTag, 90},
-       {"typedmemmove", funcTag, 91},
-       {"typedmemclr", funcTag, 92},
-       {"typedslicecopy", funcTag, 93},
-       {"selectnbsend", funcTag, 94},
-       {"selectnbrecv", funcTag, 95},
-       {"selectnbrecv2", funcTag, 97},
-       {"selectsetpc", funcTag, 98},
-       {"selectgo", funcTag, 99},
-       {"block", funcTag, 9},
-       {"makeslice", funcTag, 100},
-       {"makeslice64", funcTag, 101},
-       {"makeslicecopy", funcTag, 102},
-       {"growslice", funcTag, 104},
-       {"memmove", funcTag, 105},
-       {"memclrNoHeapPointers", funcTag, 106},
-       {"memclrHasPointers", funcTag, 106},
-       {"memequal", funcTag, 107},
-       {"memequal0", funcTag, 108},
-       {"memequal8", funcTag, 108},
-       {"memequal16", funcTag, 108},
-       {"memequal32", funcTag, 108},
-       {"memequal64", funcTag, 108},
-       {"memequal128", funcTag, 108},
-       {"f32equal", funcTag, 109},
-       {"f64equal", funcTag, 109},
-       {"c64equal", funcTag, 109},
-       {"c128equal", funcTag, 109},
-       {"strequal", funcTag, 109},
-       {"interequal", funcTag, 109},
-       {"nilinterequal", funcTag, 109},
-       {"memhash", funcTag, 110},
-       {"memhash0", funcTag, 111},
-       {"memhash8", funcTag, 111},
-       {"memhash16", funcTag, 111},
-       {"memhash32", funcTag, 111},
-       {"memhash64", funcTag, 111},
-       {"memhash128", funcTag, 111},
-       {"f32hash", funcTag, 111},
-       {"f64hash", funcTag, 111},
-       {"c64hash", funcTag, 111},
-       {"c128hash", funcTag, 111},
-       {"strhash", funcTag, 111},
-       {"interhash", funcTag, 111},
-       {"nilinterhash", funcTag, 111},
-       {"int64div", funcTag, 112},
-       {"uint64div", funcTag, 113},
-       {"int64mod", funcTag, 112},
-       {"uint64mod", funcTag, 113},
-       {"float64toint64", funcTag, 114},
-       {"float64touint64", funcTag, 115},
-       {"float64touint32", funcTag, 116},
-       {"int64tofloat64", funcTag, 117},
-       {"uint64tofloat64", funcTag, 118},
-       {"uint32tofloat64", funcTag, 119},
-       {"complex128div", funcTag, 120},
-       {"racefuncenter", funcTag, 31},
-       {"racefuncenterfp", funcTag, 9},
-       {"racefuncexit", funcTag, 9},
-       {"raceread", funcTag, 31},
-       {"racewrite", funcTag, 31},
-       {"racereadrange", funcTag, 121},
-       {"racewriterange", funcTag, 121},
-       {"msanread", funcTag, 121},
-       {"msanwrite", funcTag, 121},
-       {"msanmove", funcTag, 122},
-       {"checkptrAlignment", funcTag, 123},
-       {"checkptrArithmetic", funcTag, 125},
-       {"libfuzzerTraceCmp1", funcTag, 127},
-       {"libfuzzerTraceCmp2", funcTag, 129},
-       {"libfuzzerTraceCmp4", funcTag, 130},
-       {"libfuzzerTraceCmp8", funcTag, 131},
-       {"libfuzzerTraceConstCmp1", funcTag, 127},
-       {"libfuzzerTraceConstCmp2", funcTag, 129},
-       {"libfuzzerTraceConstCmp4", funcTag, 130},
-       {"libfuzzerTraceConstCmp8", funcTag, 131},
-       {"x86HasPOPCNT", varTag, 6},
-       {"x86HasSSE41", varTag, 6},
-       {"x86HasFMA", varTag, 6},
-       {"armHasVFPv4", varTag, 6},
-       {"arm64HasATOMICS", varTag, 6},
-}
-
-func runtimeTypes() []*types.Type {
-       var typs [132]*types.Type
-       typs[0] = types.ByteType
-       typs[1] = types.NewPtr(typs[0])
-       typs[2] = types.Types[types.TANY]
-       typs[3] = types.NewPtr(typs[2])
-       typs[4] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
-       typs[5] = types.Types[types.TUINTPTR]
-       typs[6] = types.Types[types.TBOOL]
-       typs[7] = types.Types[types.TUNSAFEPTR]
-       typs[8] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
-       typs[9] = functype(nil, nil, nil)
-       typs[10] = types.Types[types.TINTER]
-       typs[11] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])}, nil)
-       typs[12] = types.Types[types.TINT32]
-       typs[13] = types.NewPtr(typs[12])
-       typs[14] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[13])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])})
-       typs[15] = types.Types[types.TINT]
-       typs[16] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
-       typs[17] = types.Types[types.TUINT]
-       typs[18] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[17]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
-       typs[19] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}, nil)
-       typs[20] = types.Types[types.TFLOAT64]
-       typs[21] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, nil)
-       typs[22] = types.Types[types.TINT64]
-       typs[23] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, nil)
-       typs[24] = types.Types[types.TUINT64]
-       typs[25] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
-       typs[26] = types.Types[types.TCOMPLEX128]
-       typs[27] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])}, nil)
-       typs[28] = types.Types[types.TSTRING]
-       typs[29] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, nil)
-       typs[30] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
-       typs[31] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
-       typs[32] = types.NewArray(typs[0], 32)
-       typs[33] = types.NewPtr(typs[32])
-       typs[34] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[35] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[36] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[37] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[38] = types.NewSlice(typs[28])
-       typs[39] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[38])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[40] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
-       typs[41] = types.NewArray(typs[0], 4)
-       typs[42] = types.NewPtr(typs[41])
-       typs[43] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[42]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[44] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[45] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[46] = types.RuneType
-       typs[47] = types.NewSlice(typs[46])
-       typs[48] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[47])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
-       typs[49] = types.NewSlice(typs[0])
-       typs[50] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[49])})
-       typs[51] = types.NewArray(typs[46], 32)
-       typs[52] = types.NewPtr(typs[51])
-       typs[53] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[52]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[47])})
-       typs[54] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
-       typs[55] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[46]), ir.NewField(base.Pos, nil, nil, typs[15])})
-       typs[56] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
-       typs[57] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
-       typs[58] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
-       typs[59] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
-       typs[60] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2]), ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[61] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
-       typs[62] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
-       typs[63] = types.NewPtr(typs[5])
-       typs[64] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[65] = types.Types[types.TUINT32]
-       typs[66] = functype(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
-       typs[67] = types.NewMap(typs[2], typs[2])
-       typs[68] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
-       typs[69] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
-       typs[70] = functype(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
-       typs[71] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
-       typs[72] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
-       typs[73] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
-       typs[74] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[75] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[76] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[77] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
-       typs[78] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
-       typs[79] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
-       typs[80] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67])}, nil)
-       typs[81] = types.NewChan(typs[2], types.Cboth)
-       typs[82] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
-       typs[83] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
-       typs[84] = types.NewChan(typs[2], types.Crecv)
-       typs[85] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
-       typs[86] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[87] = types.NewChan(typs[2], types.Csend)
-       typs[88] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
-       typs[89] = types.NewArray(typs[0], 3)
-       typs[90] = tostruct([]*ir.Field{ir.NewField(base.Pos, lookup("enabled"), nil, typs[6]), ir.NewField(base.Pos, lookup("pad"), nil, typs[89]), ir.NewField(base.Pos, lookup("needed"), nil, typs[6]), ir.NewField(base.Pos, lookup("cgo"), nil, typs[6]), ir.NewField(base.Pos, lookup("alignme"), nil, typs[24])})
-       typs[91] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
-       typs[92] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
-       typs[93] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
-       typs[94] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[95] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[96] = types.NewPtr(typs[6])
-       typs[97] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[96]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[98] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63])}, nil)
-       typs[99] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[100] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
-       typs[101] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
-       typs[102] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
-       typs[103] = types.NewSlice(typs[2])
-       typs[104] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[103]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[103])})
-       typs[105] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
-       typs[106] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
-       typs[107] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[108] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[109] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
-       typs[110] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
-       typs[111] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
-       typs[112] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
-       typs[113] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
-       typs[114] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
-       typs[115] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
-       typs[116] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
-       typs[117] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
-       typs[118] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
-       typs[119] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
-       typs[120] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26]), ir.NewField(base.Pos, nil, nil, typs[26])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])})
-       typs[121] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
-       typs[122] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
-       typs[123] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
-       typs[124] = types.NewSlice(typs[7])
-       typs[125] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[124])}, nil)
-       typs[126] = types.Types[types.TUINT8]
-       typs[127] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[126]), ir.NewField(base.Pos, nil, nil, typs[126])}, nil)
-       typs[128] = types.Types[types.TUINT16]
-       typs[129] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[128]), ir.NewField(base.Pos, nil, nil, typs[128])}, nil)
-       typs[130] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65]), ir.NewField(base.Pos, nil, nil, typs[65])}, nil)
-       typs[131] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
-       return typs[:]
-}
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
-       "fmt"
 )
 
 func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node {
        return clo
 }
 
-// typecheckclosure typechecks an OCLOSURE node. It also creates the named
-// function associated with the closure.
-// TODO: This creation of the named function should probably really be done in a
-// separate pass from type-checking.
-func typecheckclosure(clo *ir.ClosureExpr, top int) {
-       fn := clo.Func
-       // Set current associated iota value, so iota can be used inside
-       // function in ConstSpec, see issue #22344
-       if x := getIotaValue(); x >= 0 {
-               fn.Iota = x
-       }
-
-       fn.ClosureType = typecheck(fn.ClosureType, ctxType)
-       clo.SetType(fn.ClosureType.Type())
-       fn.SetClosureCalled(top&ctxCallee != 0)
-
-       // Do not typecheck fn twice, otherwise, we will end up pushing
-       // fn to Target.Decls multiple times, causing initLSym called twice.
-       // See #30709
-       if fn.Typecheck() == 1 {
-               return
-       }
-
-       for _, ln := range fn.ClosureVars {
-               n := ln.Defn
-               if !n.Name().Captured() {
-                       n.Name().SetCaptured(true)
-                       if n.Name().Decldepth == 0 {
-                               base.Fatalf("typecheckclosure: var %v does not have decldepth assigned", n)
-                       }
-
-                       // Ignore assignments to the variable in straightline code
-                       // preceding the first capturing by a closure.
-                       if n.Name().Decldepth == decldepth {
-                               n.Name().SetAssigned(false)
-                       }
-               }
-       }
-
-       fn.Nname.SetSym(closurename(ir.CurFunc))
-       ir.MarkFunc(fn.Nname)
-       typecheckFunc(fn)
-
-       // Type check the body now, but only if we're inside a function.
-       // At top level (in a variable initialization: curfn==nil) we're not
-       // ready to type check code yet; we'll check it later, because the
-       // underlying closure function we create is added to Target.Decls.
-       if ir.CurFunc != nil && clo.Type() != nil {
-               oldfn := ir.CurFunc
-               ir.CurFunc = fn
-               olddd := decldepth
-               decldepth = 1
-               typecheckslice(fn.Body, ctxStmt)
-               decldepth = olddd
-               ir.CurFunc = oldfn
-       }
-
-       Target.Decls = append(Target.Decls, fn)
-}
-
-// globClosgen is like Func.Closgen, but for the global scope.
-var globClosgen int32
-
-// closurename generates a new unique name for a closure within
-// outerfunc.
-func closurename(outerfunc *ir.Func) *types.Sym {
-       outer := "glob."
-       prefix := "func"
-       gen := &globClosgen
-
-       if outerfunc != nil {
-               if outerfunc.OClosure != nil {
-                       prefix = ""
-               }
-
-               outer = ir.FuncName(outerfunc)
-
-               // There may be multiple functions named "_". In those
-               // cases, we can't use their individual Closgens as it
-               // would lead to name clashes.
-               if !ir.IsBlank(outerfunc.Nname) {
-                       gen = &outerfunc.Closgen
-               }
-       }
-
-       *gen++
-       return lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
-}
-
-// capturevarscomplete is set to true when the capturevars phase is done.
-var capturevarscomplete bool
-
-// capturevars is called in a separate phase after all typechecking is done.
-// It decides whether each variable captured by a closure should be captured
-// by value or by reference.
-// We use value capturing for values <= 128 bytes that are never reassigned
-// after capturing (effectively constant).
-func capturevars(fn *ir.Func) {
-       lno := base.Pos
-       base.Pos = fn.Pos()
-       cvars := fn.ClosureVars
-       out := cvars[:0]
-       for _, v := range cvars {
-               if v.Type() == nil {
-                       // If v.Type is nil, it means v looked like it
-                       // was going to be used in the closure, but
-                       // isn't. This happens in struct literals like
-                       // s{f: x} where we can't distinguish whether
-                       // f is a field identifier or expression until
-                       // resolving s.
-                       continue
-               }
-               out = append(out, v)
-
-               // type check the & of closed variables outside the closure,
-               // so that the outer frame also grabs them and knows they escape.
-               types.CalcSize(v.Type())
-
-               var outer ir.Node
-               outer = v.Outer
-               outermost := v.Defn.(*ir.Name)
-
-               // out parameters will be assigned to implicitly upon return.
-               if outermost.Class_ != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
-                       v.SetByval(true)
-               } else {
-                       outermost.Name().SetAddrtaken(true)
-                       outer = nodAddr(outer)
-               }
-
-               if base.Flag.LowerM > 1 {
-                       var name *types.Sym
-                       if v.Curfn != nil && v.Curfn.Nname != nil {
-                               name = v.Curfn.Sym()
-                       }
-                       how := "ref"
-                       if v.Byval() {
-                               how = "value"
-                       }
-                       base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width))
-               }
-
-               outer = typecheck(outer, ctxExpr)
-               fn.ClosureEnter.Append(outer)
-       }
-
-       fn.ClosureVars = out
-       base.Pos = lno
-}
-
 // transformclosure is called in a separate phase after escape analysis.
 // It transform closure bodies to properly reference captured variables.
 func transformclosure(fn *ir.Func) {
                                // we introduce function param &v *T
                                // and v remains PAUTOHEAP with &v heapaddr
                                // (accesses will implicitly deref &v).
-                               addr := NewName(lookup("&" + v.Sym().Name))
+                               addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
                                addr.SetType(types.NewPtr(v.Type()))
                                v.Heapaddr = addr
                                v = addr
                        } else {
                                // Declare variable holding addresses taken from closure
                                // and initialize in entry prologue.
-                               addr := NewName(lookup("&" + v.Sym().Name))
+                               addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
                                addr.SetType(types.NewPtr(v.Type()))
                                addr.Class_ = ir.PAUTO
                                addr.SetUsed(true)
                                v.Heapaddr = addr
                                var src ir.Node = cr
                                if v.Byval() {
-                                       src = nodAddr(cr)
+                                       src = typecheck.NodAddr(cr)
                                }
                                body = append(body, ir.NewAssignStmt(base.Pos, addr, src))
                        }
                }
 
                if len(body) > 0 {
-                       typecheckslice(body, ctxStmt)
+                       typecheck.Stmts(body)
                        fn.Enter.Set(body)
                        fn.SetNeedctxt(true)
                }
        }
 }
 
-// closureType returns the struct type used to hold all the information
-// needed in the closure for clo (clo must be a OCLOSURE node).
-// The address of a variable of the returned type can be cast to a func.
-func closureType(clo *ir.ClosureExpr) *types.Type {
-       // Create closure in the form of a composite literal.
-       // supposing the closure captures an int i and a string s
-       // and has one float64 argument and no results,
-       // the generated code looks like:
-       //
-       //      clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
-       //
-       // The use of the struct provides type information to the garbage
-       // collector so that it can walk the closure. We could use (in this case)
-       // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
-       // The information appears in the binary in the form of type descriptors;
-       // the struct is unnamed so that closures in multiple packages with the
-       // same struct type can share the descriptor.
-       fields := []*ir.Field{
-               ir.NewField(base.Pos, lookup(".F"), nil, types.Types[types.TUINTPTR]),
-       }
-       for _, v := range clo.Func.ClosureVars {
-               typ := v.Type()
-               if !v.Byval() {
-                       typ = types.NewPtr(typ)
-               }
-               fields = append(fields, ir.NewField(base.Pos, v.Sym(), nil, typ))
-       }
-       typ := tostruct(fields)
-       typ.SetNoalg(true)
-       return typ
-}
-
 func walkclosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
        fn := clo.Func
 
        }
        closuredebugruntimecheck(clo)
 
-       typ := closureType(clo)
+       typ := typecheck.ClosureType(clo)
 
        clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
        clos.SetEsc(clo.Esc())
        clos.List.Set(append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, fn.Nname)}, fn.ClosureEnter...))
 
-       addr := nodAddr(clos)
+       addr := typecheck.NodAddr(clos)
        addr.SetEsc(clo.Esc())
 
        // Force type conversion from *struct to the func type.
-       cfn := convnop(addr, clo.Type())
+       cfn := typecheck.ConvNop(addr, clo.Type())
 
        // non-escaping temp to use, if any.
        if x := clo.Prealloc; x != nil {
        return walkexpr(cfn, init)
 }
 
-func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
-       switch n.Op() {
-       case ir.ODOTINTER, ir.ODOTMETH:
-               break
-
-       default:
-               base.Fatalf("invalid typecheckpartialcall")
-       }
-       dot := n.(*ir.SelectorExpr)
-
-       // Create top-level function.
-       fn := makepartialcall(dot, dot.Type(), sym)
-       fn.SetWrapper(true)
-
-       return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
-}
-
-// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
-// for partial calls.
-func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func {
-       rcvrtype := dot.X.Type()
-       sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
-
-       if sym.Uniq() {
-               return sym.Def.(*ir.Func)
-       }
-       sym.SetUniq(true)
-
-       savecurfn := ir.CurFunc
-       saveLineNo := base.Pos
-       ir.CurFunc = nil
-
-       // Set line number equal to the line number where the method is declared.
-       var m *types.Field
-       if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
-               base.Pos = m.Pos
-       }
-       // Note: !m.Pos.IsKnown() happens for method expressions where
-       // the method is implicitly declared. The Error method of the
-       // built-in error type is one such method.  We leave the line
-       // number at the use of the method expression in this
-       // case. See issue 29389.
-
-       tfn := ir.NewFuncType(base.Pos, nil,
-               structargs(t0.Params(), true),
-               structargs(t0.Results(), false))
-
-       fn := dclfunc(sym, tfn)
-       fn.SetDupok(true)
-       fn.SetNeedctxt(true)
-
-       // Declare and initialize variable holding receiver.
-       cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
-       ptr := NewName(lookup(".this"))
-       declare(ptr, ir.PAUTO)
-       ptr.SetUsed(true)
-       var body []ir.Node
-       if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
-               ptr.SetType(rcvrtype)
-               body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr))
-       } else {
-               ptr.SetType(types.NewPtr(rcvrtype))
-               body = append(body, ir.NewAssignStmt(base.Pos, ptr, nodAddr(cr)))
-       }
-
-       call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
-       call.Args.Set(ir.ParamNames(tfn.Type()))
-       call.IsDDD = tfn.Type().IsVariadic()
-       if t0.NumResults() != 0 {
-               ret := ir.NewReturnStmt(base.Pos, nil)
-               ret.Results = []ir.Node{call}
-               body = append(body, ret)
-       } else {
-               body = append(body, call)
-       }
-
-       fn.Body.Set(body)
-       funcbody()
-
-       typecheckFunc(fn)
-       // Need to typecheck the body of the just-generated wrapper.
-       // typecheckslice() requires that Curfn is set when processing an ORETURN.
-       ir.CurFunc = fn
-       typecheckslice(fn.Body, ctxStmt)
-       sym.Def = fn
-       Target.Decls = append(Target.Decls, fn)
-       ir.CurFunc = savecurfn
-       base.Pos = saveLineNo
-
-       return fn
-}
-
-// partialCallType returns the struct type used to hold all the information
-// needed in the closure for n (n must be a OCALLPART node).
-// The address of a variable of the returned type can be cast to a func.
-func partialCallType(n *ir.CallPartExpr) *types.Type {
-       t := tostruct([]*ir.Field{
-               ir.NewField(base.Pos, lookup("F"), nil, types.Types[types.TUINTPTR]),
-               ir.NewField(base.Pos, lookup("R"), nil, n.X.Type()),
-       })
-       t.SetNoalg(true)
-       return t
-}
-
 func walkpartialcall(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
        // Create closure in the form of a composite literal.
        // For x.M with receiver (x) type T, the generated code looks like:
                n.X = cheapexpr(n.X, init)
                n.X = walkexpr(n.X, nil)
 
-               tab := typecheck(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X), ctxExpr)
+               tab := typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X))
 
                c := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
                c.SetTypecheck(1)
                init.Append(c)
        }
 
-       typ := partialCallType(n)
+       typ := typecheck.PartialCallType(n)
 
        clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
        clos.SetEsc(n.Esc())
        clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, n.Func.Nname), n.X}
 
-       addr := nodAddr(clos)
+       addr := typecheck.NodAddr(clos)
        addr.SetEsc(n.Esc())
 
        // Force type conversion from *struct to the func type.
-       cfn := convnop(addr, n.Type())
+       cfn := typecheck.ConvNop(addr, n.Type())
 
        // non-escaping temp to use, if any.
        if x := n.Prealloc; x != nil {
 
        "bytes"
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/src"
        "fmt"
-       "strings"
 )
 
 func EnableNoWriteBarrierRecCheck() {
 
 var nowritebarrierrecCheck *nowritebarrierrecChecker
 
-// redeclare emits a diagnostic about symbol s being redeclared at pos.
-func redeclare(pos src.XPos, s *types.Sym, where string) {
-       if !s.Lastlineno.IsKnown() {
-               pkgName := dotImportRefs[s.Def.(*ir.Ident)]
-               base.ErrorfAt(pos, "%v redeclared %s\n"+
-                       "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
-       } else {
-               prevPos := s.Lastlineno
-
-               // When an import and a declaration collide in separate files,
-               // present the import as the "redeclared", because the declaration
-               // is visible where the import is, but not vice versa.
-               // See issue 4510.
-               if s.Def == nil {
-                       pos, prevPos = prevPos, pos
-               }
-
-               base.ErrorfAt(pos, "%v redeclared %s\n"+
-                       "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
-       }
-}
-
-var vargen int
-
-// declare individual names - var, typ, const
-
-var declare_typegen int
-
-// declare records that Node n declares symbol n.Sym in the specified
-// declaration context.
-func declare(n *ir.Name, ctxt ir.Class) {
-       if ir.IsBlank(n) {
-               return
-       }
-
-       s := n.Sym()
-
-       // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
-       if !inimport && !typecheckok && s.Pkg != types.LocalPkg {
-               base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
-       }
-
-       gen := 0
-       if ctxt == ir.PEXTERN {
-               if s.Name == "init" {
-                       base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
-               }
-               if s.Name == "main" && s.Pkg.Name == "main" {
-                       base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
-               }
-               Target.Externs = append(Target.Externs, n)
-       } else {
-               if ir.CurFunc == nil && ctxt == ir.PAUTO {
-                       base.Pos = n.Pos()
-                       base.Fatalf("automatic outside function")
-               }
-               if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
-                       ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
-               }
-               if n.Op() == ir.OTYPE {
-                       declare_typegen++
-                       gen = declare_typegen
-               } else if n.Op() == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") {
-                       vargen++
-                       gen = vargen
-               }
-               types.Pushdcl(s)
-               n.Curfn = ir.CurFunc
-       }
-
-       if ctxt == ir.PAUTO {
-               n.SetFrameOffset(0)
-       }
-
-       if s.Block == types.Block {
-               // functype will print errors about duplicate function arguments.
-               // Don't repeat the error here.
-               if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
-                       redeclare(n.Pos(), s, "in this block")
-               }
-       }
-
-       s.Block = types.Block
-       s.Lastlineno = base.Pos
-       s.Def = n
-       n.Vargen = int32(gen)
-       n.Class_ = ctxt
-       if ctxt == ir.PFUNC {
-               n.Sym().SetFunc(true)
-       }
-
-       autoexport(n, ctxt)
-}
-
-// declare variables from grammar
-// new_name_list (type | [type] = expr_list)
-func variter(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
-       var init []ir.Node
-       doexpr := len(el) > 0
-
-       if len(el) == 1 && len(vl) > 1 {
-               e := el[0]
-               as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-               as2.Rhs = []ir.Node{e}
-               for _, v := range vl {
-                       as2.Lhs.Append(v)
-                       declare(v, dclcontext)
-                       v.Ntype = t
-                       v.Defn = as2
-                       if ir.CurFunc != nil {
-                               init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
-                       }
-               }
-
-               return append(init, as2)
-       }
-
-       for i, v := range vl {
-               var e ir.Node
-               if doexpr {
-                       if i >= len(el) {
-                               base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
-                               break
-                       }
-                       e = el[i]
-               }
-
-               declare(v, dclcontext)
-               v.Ntype = t
-
-               if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
-                       if ir.CurFunc != nil {
-                               init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
-                       }
-                       as := ir.NewAssignStmt(base.Pos, v, e)
-                       init = append(init, as)
-                       if e != nil {
-                               v.Defn = as
-                       }
-               }
-       }
-
-       if len(el) > len(vl) {
-               base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
-       }
-       return init
-}
-
 // oldname returns the Node that declares symbol s in the current scope.
 // If no such Node currently exists, an ONONAME Node is returned instead.
 // Automatically creates a new closure variable if the referenced symbol was
                c := n.Name().Innermost
                if c == nil || c.Curfn != ir.CurFunc {
                        // Do not have a closure var for the active closure yet; make one.
-                       c = NewName(s)
+                       c = typecheck.NewName(s)
                        c.Class_ = ir.PAUTOHEAP
                        c.SetIsClosureVar(true)
                        c.SetIsDDD(n.IsDDD())
        return n
 }
 
-// := declarations
-func colasname(n ir.Node) bool {
-       switch n.Op() {
-       case ir.ONAME,
-               ir.ONONAME,
-               ir.OPACK,
-               ir.OTYPE,
-               ir.OLITERAL:
-               return n.Sym() != nil
-       }
-
-       return false
-}
-
-func colasdefn(left []ir.Node, defn ir.Node) {
-       for _, n := range left {
-               if n.Sym() != nil {
-                       n.Sym().SetUniq(true)
-               }
-       }
-
-       var nnew, nerr int
-       for i, n := range left {
-               if ir.IsBlank(n) {
-                       continue
-               }
-               if !colasname(n) {
-                       base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n)
-                       nerr++
-                       continue
-               }
-
-               if !n.Sym().Uniq() {
-                       base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym())
-                       n.SetDiag(true)
-                       nerr++
-                       continue
-               }
-
-               n.Sym().SetUniq(false)
-               if n.Sym().Block == types.Block {
-                       continue
-               }
-
-               nnew++
-               n := NewName(n.Sym())
-               declare(n, dclcontext)
-               n.Defn = defn
-               defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
-               left[i] = n
-       }
-
-       if nnew == 0 && nerr == 0 {
-               base.ErrorfAt(defn.Pos(), "no new variables on left side of :=")
-       }
-}
-
-// declare the function proper
-// and declare the arguments.
-// called in extern-declaration context
-// returns in auto-declaration context.
-func funchdr(fn *ir.Func) {
-       // change the declaration context from extern to auto
-       funcStack = append(funcStack, funcStackEnt{ir.CurFunc, dclcontext})
-       ir.CurFunc = fn
-       dclcontext = ir.PAUTO
-
-       types.Markdcl()
-
-       if fn.Nname.Ntype != nil {
-               funcargs(fn.Nname.Ntype.(*ir.FuncType))
-       } else {
-               funcargs2(fn.Type())
-       }
-}
-
-func funcargs(nt *ir.FuncType) {
-       if nt.Op() != ir.OTFUNC {
-               base.Fatalf("funcargs %v", nt.Op())
-       }
-
-       // re-start the variable generation number
-       // we want to use small numbers for the return variables,
-       // so let them have the chunk starting at 1.
-       //
-       // TODO(mdempsky): This is ugly, and only necessary because
-       // esc.go uses Vargen to figure out result parameters' index
-       // within the result tuple.
-       vargen = len(nt.Results)
-
-       // declare the receiver and in arguments.
-       if nt.Recv != nil {
-               funcarg(nt.Recv, ir.PPARAM)
-       }
-       for _, n := range nt.Params {
-               funcarg(n, ir.PPARAM)
-       }
-
-       oldvargen := vargen
-       vargen = 0
-
-       // declare the out arguments.
-       gen := len(nt.Params)
-       for _, n := range nt.Results {
-               if n.Sym == nil {
-                       // Name so that escape analysis can track it. ~r stands for 'result'.
-                       n.Sym = lookupN("~r", gen)
-                       gen++
-               }
-               if n.Sym.IsBlank() {
-                       // Give it a name so we can assign to it during return. ~b stands for 'blank'.
-                       // The name must be different from ~r above because if you have
-                       //      func f() (_ int)
-                       //      func g() int
-                       // f is allowed to use a plain 'return' with no arguments, while g is not.
-                       // So the two cases must be distinguished.
-                       n.Sym = lookupN("~b", gen)
-                       gen++
-               }
-
-               funcarg(n, ir.PPARAMOUT)
-       }
-
-       vargen = oldvargen
-}
-
-func funcarg(n *ir.Field, ctxt ir.Class) {
-       if n.Sym == nil {
-               return
-       }
-
-       name := ir.NewNameAt(n.Pos, n.Sym)
-       n.Decl = name
-       name.Ntype = n.Ntype
-       name.SetIsDDD(n.IsDDD)
-       declare(name, ctxt)
-
-       vargen++
-       n.Decl.Vargen = int32(vargen)
-}
-
-// Same as funcargs, except run over an already constructed TFUNC.
-// This happens during import, where the hidden_fndcl rule has
-// used functype directly to parse the function's type.
-func funcargs2(t *types.Type) {
-       if t.Kind() != types.TFUNC {
-               base.Fatalf("funcargs2 %v", t)
-       }
-
-       for _, f := range t.Recvs().Fields().Slice() {
-               funcarg2(f, ir.PPARAM)
-       }
-       for _, f := range t.Params().Fields().Slice() {
-               funcarg2(f, ir.PPARAM)
-       }
-       for _, f := range t.Results().Fields().Slice() {
-               funcarg2(f, ir.PPARAMOUT)
-       }
-}
-
-func funcarg2(f *types.Field, ctxt ir.Class) {
-       if f.Sym == nil {
-               return
-       }
-       n := ir.NewNameAt(f.Pos, f.Sym)
-       f.Nname = n
-       n.SetType(f.Type)
-       n.SetIsDDD(f.IsDDD())
-       declare(n, ctxt)
-}
-
-var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
-
-type funcStackEnt struct {
-       curfn      *ir.Func
-       dclcontext ir.Class
-}
-
-func CheckFuncStack() {
-       if len(funcStack) != 0 {
-               base.Fatalf("funcStack is non-empty: %v", len(funcStack))
-       }
-}
-
-// finish the body.
-// called in auto-declaration context.
-// returns in extern-declaration context.
-func funcbody() {
-       // change the declaration context from auto to previous context
-       types.Popdcl()
-       var e funcStackEnt
-       funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
-       ir.CurFunc, dclcontext = e.curfn, e.dclcontext
-}
-
-// structs, functions, and methods.
-// they don't belong here, but where do they belong?
-func checkembeddedtype(t *types.Type) {
-       if t == nil {
-               return
-       }
-
-       if t.Sym() == nil && t.IsPtr() {
-               t = t.Elem()
-               if t.IsInterface() {
-                       base.Errorf("embedded type cannot be a pointer to interface")
-               }
-       }
-
-       if t.IsPtr() || t.IsUnsafePtr() {
-               base.Errorf("embedded type cannot be a pointer")
-       } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
-               t.ForwardType().Embedlineno = base.Pos
-       }
-}
-
-// checkdupfields emits errors for duplicately named fields or methods in
-// a list of struct or interface types.
-func checkdupfields(what string, fss ...[]*types.Field) {
-       seen := make(map[*types.Sym]bool)
-       for _, fs := range fss {
-               for _, f := range fs {
-                       if f.Sym == nil || f.Sym.IsBlank() {
-                               continue
-                       }
-                       if seen[f.Sym] {
-                               base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
-                               continue
-                       }
-                       seen[f.Sym] = true
-               }
-       }
-}
-
-// convert a parsed id/type list into
-// a type for struct/interface/arglist
-func tostruct(l []*ir.Field) *types.Type {
-       lno := base.Pos
-
-       fields := make([]*types.Field, len(l))
-       for i, n := range l {
-               base.Pos = n.Pos
-
-               if n.Ntype != nil {
-                       n.Type = typecheckNtype(n.Ntype).Type()
-                       n.Ntype = nil
-               }
-               f := types.NewField(n.Pos, n.Sym, n.Type)
-               if n.Embedded {
-                       checkembeddedtype(n.Type)
-                       f.Embedded = 1
-               }
-               f.Note = n.Note
-               fields[i] = f
-       }
-       checkdupfields("field", fields)
-
-       base.Pos = lno
-       return types.NewStruct(types.LocalPkg, fields)
-}
-
-func tointerface(nmethods []*ir.Field) *types.Type {
-       if len(nmethods) == 0 {
-               return types.Types[types.TINTER]
-       }
-
-       lno := base.Pos
-
-       methods := make([]*types.Field, len(nmethods))
-       for i, n := range nmethods {
-               base.Pos = n.Pos
-               if n.Ntype != nil {
-                       n.Type = typecheckNtype(n.Ntype).Type()
-                       n.Ntype = nil
-               }
-               methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
-       }
-
-       base.Pos = lno
-       return types.NewInterface(types.LocalPkg, methods)
-}
-
 func fakeRecv() *ir.Field {
        return ir.NewField(base.Pos, nil, nil, types.FakeRecvType())
 }
 
-func fakeRecvField() *types.Field {
-       return types.NewField(src.NoXPos, nil, types.FakeRecvType())
-}
-
-// turn a parsed function declaration into a type
-func functype(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
-       funarg := func(n *ir.Field) *types.Field {
-               lno := base.Pos
-               base.Pos = n.Pos
-
-               if n.Ntype != nil {
-                       n.Type = typecheckNtype(n.Ntype).Type()
-                       n.Ntype = nil
-               }
-
-               f := types.NewField(n.Pos, n.Sym, n.Type)
-               f.SetIsDDD(n.IsDDD)
-               if n.Decl != nil {
-                       n.Decl.SetType(f.Type)
-                       f.Nname = n.Decl
-               }
-
-               base.Pos = lno
-               return f
-       }
-       funargs := func(nn []*ir.Field) []*types.Field {
-               res := make([]*types.Field, len(nn))
-               for i, n := range nn {
-                       res[i] = funarg(n)
-               }
-               return res
-       }
-
-       var recv *types.Field
-       if nrecv != nil {
-               recv = funarg(nrecv)
-       }
-
-       t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults))
-       checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
-       return t
-}
-
-// Add a method, declared as a function.
-// - msym is the method symbol
-// - t is function type (with receiver)
-// Returns a pointer to the existing or added Field; or nil if there's an error.
-func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
-       if msym == nil {
-               base.Fatalf("no method symbol")
-       }
-
-       // get parent type sym
-       rf := t.Recv() // ptr to this structure
-       if rf == nil {
-               base.Errorf("missing receiver")
-               return nil
-       }
-
-       mt := types.ReceiverBaseType(rf.Type)
-       if mt == nil || mt.Sym() == nil {
-               pa := rf.Type
-               t := pa
-               if t != nil && t.IsPtr() {
-                       if t.Sym() != nil {
-                               base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
-                               return nil
-                       }
-                       t = t.Elem()
-               }
-
-               switch {
-               case t == nil || t.Broke():
-                       // rely on typecheck having complained before
-               case t.Sym() == nil:
-                       base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
-               case t.IsPtr():
-                       base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
-               case t.IsInterface():
-                       base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
-               default:
-                       // Should have picked off all the reasons above,
-                       // but just in case, fall back to generic error.
-                       base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
-               }
-               return nil
-       }
-
-       if local && mt.Sym().Pkg != types.LocalPkg {
-               base.Errorf("cannot define new methods on non-local type %v", mt)
-               return nil
-       }
-
-       if msym.IsBlank() {
-               return nil
-       }
-
-       if mt.IsStruct() {
-               for _, f := range mt.Fields().Slice() {
-                       if f.Sym == msym {
-                               base.Errorf("type %v has both field and method named %v", mt, msym)
-                               f.SetBroke(true)
-                               return nil
-                       }
-               }
-       }
-
-       for _, f := range mt.Methods().Slice() {
-               if msym.Name != f.Sym.Name {
-                       continue
-               }
-               // types.Identical only checks that incoming and result parameters match,
-               // so explicitly check that the receiver parameters match too.
-               if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
-                       base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
-               }
-               return f
-       }
-
-       f := types.NewField(base.Pos, msym, t)
-       f.Nname = n.Nname
-       f.SetNointerface(nointerface)
-
-       mt.Methods().Append(f)
-       return f
-}
-
 // funcsym returns s·f.
 func funcsym(s *types.Sym) *types.Sym {
        // funcsymsmu here serves to protect not just mutations of funcsyms (below),
        }
 }
 
-func dclfunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
-       if tfn.Op() != ir.OTFUNC {
-               base.Fatalf("expected OTFUNC node, got %v", tfn)
-       }
-
-       fn := ir.NewFunc(base.Pos)
-       fn.Nname = ir.NewFuncNameAt(base.Pos, sym, fn)
-       fn.Nname.Defn = fn
-       fn.Nname.Ntype = tfn
-       ir.MarkFunc(fn.Nname)
-       funchdr(fn)
-       fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
-       return fn
-}
-
 type nowritebarrierrecChecker struct {
        // extraCalls contains extra function calls that may not be
        // visible during later analysis. It maps from the ODCLFUNC of
        // important to handle it for this check, so we model it
        // directly. This has to happen before transformclosure since
        // it's a lot harder to work out the argument after.
-       for _, n := range Target.Decls {
+       for _, n := range typecheck.Target.Decls {
                if n.Op() != ir.ODCLFUNC {
                        continue
                }
        // q is the queue of ODCLFUNC Nodes to visit in BFS order.
        var q ir.NameQueue
 
-       for _, n := range Target.Decls {
+       for _, n := range typecheck.Target.Decls {
                if n.Op() != ir.ODCLFUNC {
                        continue
                }
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
 
                p.errorAt(pos, "go:embed cannot apply to var without type")
                return exprs
        }
-       if dclcontext != ir.PEXTERN {
+       if typecheck.DeclContext != ir.PEXTERN {
                p.errorAt(pos, "go:embed cannot apply to var inside func")
                return exprs
        }
 
        v := names[0]
-       Target.Embeds = append(Target.Embeds, v)
+       typecheck.Target.Embeds = append(typecheck.Target.Embeds, v)
        v.Embed = new([]ir.Embed)
        for _, e := range embeds {
                *v.Embed = append(*v.Embed, ir.Embed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns})
 }
 
 func dumpembeds() {
-       for _, v := range Target.Embeds {
+       for _, v := range typecheck.Target.Embeds {
                initEmbed(v)
        }
 }
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
        "fmt"
 
        case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
                call := call.(*ir.CallExpr)
-               fixVariadicCall(call)
+               typecheck.FixVariadicCall(call)
 
                // Pick out the function callee, if statically known.
                var fn *ir.Name
                return "too large for stack"
        }
 
-       if n.Op() == ir.OCLOSURE && closureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
+       if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
                return "too large for stack"
        }
-       if n.Op() == ir.OCALLPART && partialCallType(n.(*ir.CallPartExpr)).Size() >= ir.MaxImplicitStackVarSize {
+       if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.CallPartExpr)).Size() >= ir.MaxImplicitStackVarSize {
                return "too large for stack"
        }
 
 
        // Allocate a local stack variable to hold the pointer to the heap copy.
        // temp will add it to the function declaration list automatically.
-       heapaddr := temp(types.NewPtr(n.Type()))
-       heapaddr.SetSym(lookup("&" + n.Sym().Name))
+       heapaddr := typecheck.Temp(types.NewPtr(n.Type()))
+       heapaddr.SetSym(typecheck.Lookup("&" + n.Sym().Name))
        heapaddr.SetPos(n.Pos())
 
        // Unset AutoTemp to persist the &foo variable name through SSA to
                // Preserve a copy so we can still write code referring to the original,
                // and substitute that copy into the function declaration list
                // so that analyses of the local (on-stack) variables use it.
-               stackcopy := NewName(n.Sym())
+               stackcopy := typecheck.NewName(n.Sym())
                stackcopy.SetType(n.Type())
                stackcopy.SetFrameOffset(n.FrameOffset())
                stackcopy.Class_ = n.Class_
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/bio"
-       "cmd/internal/src"
        "fmt"
        "go/constant"
 )
        }
 }
 
-// exportsym marks n for export (or reexport).
-func exportsym(n *ir.Name) {
-       if n.Sym().OnExportList() {
-               return
-       }
-       n.Sym().SetOnExportList(true)
-
-       if base.Flag.E != 0 {
-               fmt.Printf("export symbol %v\n", n.Sym())
-       }
-
-       Target.Exports = append(Target.Exports, n)
-}
-
-func initname(s string) bool {
-       return s == "init"
-}
-
-func autoexport(n *ir.Name, ctxt ir.Class) {
-       if n.Sym().Pkg != types.LocalPkg {
-               return
-       }
-       if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || dclcontext != ir.PEXTERN {
-               return
-       }
-       if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
-               return
-       }
-
-       if types.IsExported(n.Sym().Name) || initname(n.Sym().Name) {
-               exportsym(n)
-       }
-       if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
-               n.Sym().SetAsm(true)
-               Target.Asms = append(Target.Asms, n)
-       }
-}
-
 func dumpexport(bout *bio.Writer) {
        p := &exporter{marked: make(map[*types.Type]bool)}
-       for _, n := range Target.Exports {
+       for _, n := range typecheck.Target.Exports {
                p.markObject(n)
        }
 
        // The linker also looks for the $$ marker - use char after $$ to distinguish format.
        exportf(bout, "\n$$B\n") // indicate binary export format
        off := bout.Offset()
-       iexport(bout.Writer)
+       typecheck.WriteExports(bout.Writer)
        size := bout.Offset() - off
        exportf(bout, "\n$$\n")
 
        }
 }
 
-func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name {
-       if n := s.PkgDef(); n != nil {
-               base.Fatalf("importsym of symbol that already exists: %v", n)
-       }
-
-       n := ir.NewDeclNameAt(pos, op, s)
-       n.Class_ = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too?
-       s.SetPkgDef(n)
-       s.Importdef = ipkg
-       return n
-}
-
-// importtype returns the named type declared by symbol s.
-// If no such type has been declared yet, a forward declaration is returned.
-// ipkg is the package being imported
-func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *ir.Name {
-       n := importsym(ipkg, pos, s, ir.OTYPE, ir.PEXTERN)
-       n.SetType(types.NewNamed(n))
-       return n
-}
-
-// importobj declares symbol s as an imported object representable by op.
-// ipkg is the package being imported
-func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name {
-       n := importsym(ipkg, pos, s, op, ctxt)
-       n.SetType(t)
-       if ctxt == ir.PFUNC {
-               n.Sym().SetFunc(true)
-       }
-       return n
-}
-
-// importconst declares symbol s as an imported constant with type t and value val.
-// ipkg is the package being imported
-func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name {
-       n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t)
-       n.SetVal(val)
-       return n
-}
-
-// importfunc declares symbol s as an imported function with type t.
-// ipkg is the package being imported
-func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
-       n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
-
-       fn := ir.NewFunc(pos)
-       fn.SetType(t)
-       n.SetFunc(fn)
-       fn.Nname = n
-
-       return n
-}
-
-// importvar declares symbol s as an imported variable with type t.
-// ipkg is the package being imported
-func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
-       return importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t)
-}
-
-// importalias declares symbol s as an imported type alias with type t.
-// ipkg is the package being imported
-func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
-       return importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t)
-}
-
 func dumpasmhdr() {
        b, err := bio.Create(base.Flag.AsmHdr)
        if err != nil {
                base.Fatalf("%v", err)
        }
        fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", types.LocalPkg.Name)
-       for _, n := range Target.Asms {
+       for _, n := range typecheck.Target.Asms {
                if n.Sym().IsBlank() {
                        continue
                }
 
        b.Close()
 }
+
+type exporter struct {
+       marked map[*types.Type]bool // types already seen by markType
+}
+
+// markObject visits a reachable object.
+func (p *exporter) markObject(n ir.Node) {
+       if n.Op() == ir.ONAME {
+               n := n.(*ir.Name)
+               if n.Class_ == ir.PFUNC {
+                       inlFlood(n, typecheck.Export)
+               }
+       }
+
+       p.markType(n.Type())
+}
+
+// markType recursively visits types reachable from t to identify
+// functions whose inline bodies may be needed.
+func (p *exporter) markType(t *types.Type) {
+       if p.marked[t] {
+               return
+       }
+       p.marked[t] = true
+
+       // If this is a named type, mark all of its associated
+       // methods. Skip interface types because t.Methods contains
+       // only their unexpanded method set (i.e., exclusive of
+       // interface embeddings), and the switch statement below
+       // handles their full method set.
+       if t.Sym() != nil && t.Kind() != types.TINTER {
+               for _, m := range t.Methods().Slice() {
+                       if types.IsExported(m.Sym.Name) {
+                               p.markObject(ir.AsNode(m.Nname))
+                       }
+               }
+       }
+
+       // Recursively mark any types that can be produced given a
+       // value of type t: dereferencing a pointer; indexing or
+       // iterating over an array, slice, or map; receiving from a
+       // channel; accessing a struct field or interface method; or
+       // calling a function.
+       //
+       // Notably, we don't mark function parameter types, because
+       // the user already needs some way to construct values of
+       // those types.
+       switch t.Kind() {
+       case types.TPTR, types.TARRAY, types.TSLICE:
+               p.markType(t.Elem())
+
+       case types.TCHAN:
+               if t.ChanDir().CanRecv() {
+                       p.markType(t.Elem())
+               }
+
+       case types.TMAP:
+               p.markType(t.Key())
+               p.markType(t.Elem())
+
+       case types.TSTRUCT:
+               for _, f := range t.FieldSlice() {
+                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
+                               p.markType(f.Type)
+                       }
+               }
+
+       case types.TFUNC:
+               for _, f := range t.Results().FieldSlice() {
+                       p.markType(f.Type)
+               }
+
+       case types.TINTER:
+               for _, f := range t.FieldSlice() {
+                       if types.IsExported(f.Sym.Name) {
+                               p.markType(f.Type)
+                       }
+               }
+       }
+}
 
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-       "cmd/internal/obj"
-       "cmd/internal/src"
-       "strconv"
-)
-
-// sysfunc looks up Go function name in package runtime. This function
-// must follow the internal calling convention.
-func sysfunc(name string) *obj.LSym {
-       s := ir.Pkgs.Runtime.Lookup(name)
-       s.SetFunc(true)
-       return s.Linksym()
-}
-
-// sysvar looks up a variable (or assembly function) name in package
-// runtime. If this is a function, it may have a special calling
-// convention.
-func sysvar(name string) *obj.LSym {
-       return ir.Pkgs.Runtime.Lookup(name).Linksym()
-}
-
-// autotmpname returns the name for an autotmp variable numbered n.
-func autotmpname(n int) string {
-       // Give each tmp a different name so that they can be registerized.
-       // Add a preceding . to avoid clashing with legal names.
-       const prefix = ".autotmp_"
-       // Start with a buffer big enough to hold a large n.
-       b := []byte(prefix + "      ")[:len(prefix)]
-       b = strconv.AppendInt(b, int64(n), 10)
-       return types.InternString(b)
-}
-
-// make a new Node off the books
-func tempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
-       if curfn == nil {
-               base.Fatalf("no curfn for tempAt")
-       }
-       if curfn.Op() == ir.OCLOSURE {
-               ir.Dump("tempAt", curfn)
-               base.Fatalf("adding tempAt to wrong closure function")
-       }
-       if t == nil {
-               base.Fatalf("tempAt called with nil type")
-       }
-
-       s := &types.Sym{
-               Name: autotmpname(len(curfn.Dcl)),
-               Pkg:  types.LocalPkg,
-       }
-       n := ir.NewNameAt(pos, s)
-       s.Def = n
-       n.SetType(t)
-       n.Class_ = ir.PAUTO
-       n.SetEsc(ir.EscNever)
-       n.Curfn = curfn
-       n.SetUsed(true)
-       n.SetAutoTemp(true)
-       curfn.Dcl = append(curfn.Dcl, n)
-
-       types.CalcSize(t)
-
-       return n
-}
-
-func temp(t *types.Type) *ir.Name {
-       return tempAt(base.Pos, ir.CurFunc, t)
-}
 
 package gc
 
 import (
-       "cmd/compile/internal/ir"
        "cmd/compile/internal/ssa"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
 
 var pragcgobuf [][]string
 
-var decldepth int32
-
-var inimport bool // set during import
-
 var zerosize int64
 
-var (
-       okforeq    [types.NTYPE]bool
-       okforadd   [types.NTYPE]bool
-       okforand   [types.NTYPE]bool
-       okfornone  [types.NTYPE]bool
-       okforbool  [types.NTYPE]bool
-       okforcap   [types.NTYPE]bool
-       okforlen   [types.NTYPE]bool
-       okforarith [types.NTYPE]bool
-)
-
-var (
-       okfor [ir.OEND][]bool
-       iscmp [ir.OEND]bool
-)
-
 var (
        funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
        funcsyms   []*types.Sym
 )
 
-var dclcontext ir.Class // PEXTERN/PAUTO
-
-var typecheckok bool
-
 // interface to back end
 
 type Arch struct {
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/ssa"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/objabi"
 
        // Q: is this needed?
        savepos := base.Pos
-       savedclcontext := dclcontext
+       savedclcontext := typecheck.DeclContext
        savedcurfn := ir.CurFunc
 
        base.Pos = base.AutogeneratedPos
-       dclcontext = ir.PEXTERN
+       typecheck.DeclContext = ir.PEXTERN
 
        // At the moment we don't support wrapping a method, we'd need machinery
        // below to handle the receiver. Panic if we see this scenario.
        var noReceiver *ir.Field
        tfn := ir.NewFuncType(base.Pos,
                noReceiver,
-               structargs(ft.Params(), true),
-               structargs(ft.Results(), false))
+               typecheck.NewFuncParams(ft.Params(), true),
+               typecheck.NewFuncParams(ft.Results(), false))
 
        // Reuse f's types.Sym to create a new ODCLFUNC/function.
-       fn := dclfunc(f.Nname.Sym(), tfn)
+       fn := typecheck.DeclFunc(f.Nname.Sym(), tfn)
        fn.SetDupok(true)
        fn.SetWrapper(true) // ignore frame for panic+recover matching
 
        }
        fn.Body.Append(tail)
 
-       funcbody()
+       typecheck.FinishFuncBody()
        if base.Debug.DclStack != 0 {
                types.CheckDclstack()
        }
 
-       typecheckFunc(fn)
+       typecheck.Func(fn)
        ir.CurFunc = fn
-       typecheckslice(fn.Body, ctxStmt)
+       typecheck.Stmts(fn.Body)
 
        escapeFuncs([]*ir.Func{fn}, false)
 
-       Target.Decls = append(Target.Decls, fn)
+       typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
 
        // Restore previous context.
        base.Pos = savepos
-       dclcontext = savedclcontext
+       typecheck.DeclContext = savedclcontext
        ir.CurFunc = savedcurfn
 }
 
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
 )
 // the name, normally "pkg.init", is altered to "pkg.init.0".
 var renameinitgen int
 
-// Function collecting autotmps generated during typechecking,
-// to be included in the package-level init function.
-var initTodo = ir.NewFunc(base.Pos)
-
 func renameinit() *types.Sym {
-       s := lookupN("init.", renameinitgen)
+       s := typecheck.LookupNum("init.", renameinitgen)
        renameinitgen++
        return s
 }
 //   2) Initialize all the variables that have initializers.
 //   3) Run any init functions.
 func fninit() *ir.Name {
-       nf := initOrder(Target.Decls)
+       nf := initOrder(typecheck.Target.Decls)
 
        var deps []*obj.LSym // initTask records for packages the current package depends on
        var fns []*obj.LSym  // functions to call for package initialization
 
        // Find imported packages with init tasks.
-       for _, pkg := range Target.Imports {
-               n := resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
+       for _, pkg := range typecheck.Target.Imports {
+               n := typecheck.Resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
                if n.Op() == ir.ONONAME {
                        continue
                }
        // Make a function that contains all the initialization statements.
        if len(nf) > 0 {
                base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
-               initializers := lookup("init")
-               fn := dclfunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
-               for _, dcl := range initTodo.Dcl {
+               initializers := typecheck.Lookup("init")
+               fn := typecheck.DeclFunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
+               for _, dcl := range typecheck.InitTodoFunc.Dcl {
                        dcl.Curfn = fn
                }
-               fn.Dcl = append(fn.Dcl, initTodo.Dcl...)
-               initTodo.Dcl = nil
+               fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
+               typecheck.InitTodoFunc.Dcl = nil
 
                fn.Body.Set(nf)
-               funcbody()
+               typecheck.FinishFuncBody()
 
-               typecheckFunc(fn)
+               typecheck.Func(fn)
                ir.CurFunc = fn
-               typecheckslice(nf, ctxStmt)
+               typecheck.Stmts(nf)
                ir.CurFunc = nil
-               Target.Decls = append(Target.Decls, fn)
+               typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
                fns = append(fns, initializers.Linksym())
        }
-       if initTodo.Dcl != nil {
+       if typecheck.InitTodoFunc.Dcl != nil {
                // We only generate temps using initTodo if there
                // are package-scope initialization statements, so
                // something's weird if we get here.
                base.Fatalf("initTodo still has declarations")
        }
-       initTodo = nil
+       typecheck.InitTodoFunc = nil
 
        // Record user init functions.
-       for _, fn := range Target.Inits {
+       for _, fn := range typecheck.Target.Inits {
                // Skip init functions with empty bodies.
                if len(fn.Body) == 1 {
                        if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
        }
 
        // Make an .inittask structure.
-       sym := lookup(".inittask")
-       task := NewName(sym)
+       sym := typecheck.Lookup(".inittask")
+       task := typecheck.NewName(sym)
        task.SetType(types.Types[types.TUINT8]) // fake type
        task.Class_ = ir.PEXTERN
        sym.Def = task
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/src"
 
 func InlinePackage() {
        // Find functions that can be inlined and clone them before walk expands them.
-       ir.VisitFuncsBottomUp(Target.Decls, func(list []*ir.Func, recursive bool) {
+       ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
                numfns := numNonClosures(list)
                for _, n := range list {
                        if !recursive || numfns > 1 {
        })
 }
 
-// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
-// the ->sym can be re-used in the local package, so peel it off the receiver's type.
-func fnpkg(fn *ir.Name) *types.Pkg {
-       if ir.IsMethod(fn) {
-               // method
-               rcvr := fn.Type().Recv().Type
-
-               if rcvr.IsPtr() {
-                       rcvr = rcvr.Elem()
-               }
-               if rcvr.Sym() == nil {
-                       base.Fatalf("receiver with no sym: [%v] %L  (%v)", fn.Sym(), fn, rcvr)
-               }
-               return rcvr.Sym().Pkg
-       }
-
-       // non-method
-       return fn.Sym().Pkg
-}
-
-// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
-// because they're a copy of an already checked body.
-func typecheckinl(fn *ir.Func) {
-       lno := ir.SetPos(fn.Nname)
-
-       expandInline(fn)
-
-       // typecheckinl is only for imported functions;
-       // their bodies may refer to unsafe as long as the package
-       // was marked safe during import (which was checked then).
-       // the ->inl of a local function has been typechecked before caninl copied it.
-       pkg := fnpkg(fn.Nname)
-
-       if pkg == types.LocalPkg || pkg == nil {
-               return // typecheckinl on local function
-       }
-
-       if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
-               fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
-       }
-
-       savefn := ir.CurFunc
-       ir.CurFunc = fn
-       typecheckslice(fn.Inl.Body, ctxStmt)
-       ir.CurFunc = savefn
-
-       // During expandInline (which imports fn.Func.Inl.Body),
-       // declarations are added to fn.Func.Dcl by funcHdr(). Move them
-       // to fn.Func.Inl.Dcl for consistency with how local functions
-       // behave. (Append because typecheckinl may be called multiple
-       // times.)
-       fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...)
-       fn.Dcl = nil
-
-       base.Pos = lno
-}
-
 // Caninl determines whether fn is inlineable.
 // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
 // fn and ->nbody will already have been typechecked.
        }
        fn.SetExportInline(true)
 
-       typecheckinl(fn)
+       typecheck.ImportedBody(fn)
 
        // Recursively identify all referenced functions for
        // reexport. We want to include even non-called functions,
                        as.Rhs.Set(inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr)))
                        as.SetOp(ir.OAS2)
                        as.SetTypecheck(0)
-                       n = typecheck(as, ctxStmt)
+                       n = typecheck.Stmt(as)
                }
        }
 
                inlMap[fn] = false
        }()
        if base.Debug.TypecheckInl == 0 {
-               typecheckinl(fn)
+               typecheck.ImportedBody(fn)
        }
 
        // We have a function node, and it has an inlineable body.
                        }
 
                        if v.Byval() {
-                               iv := typecheck(inlvar(v), ctxExpr)
+                               iv := typecheck.Expr(inlvar(v))
                                ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, iv))
-                               ninit.Append(typecheck(ir.NewAssignStmt(base.Pos, iv, o), ctxStmt))
+                               ninit.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, iv, o)))
                                inlvars[v] = iv
                        } else {
-                               addr := NewName(lookup("&" + v.Sym().Name))
+                               addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
                                addr.SetType(types.NewPtr(v.Type()))
-                               ia := typecheck(inlvar(addr), ctxExpr)
+                               ia := typecheck.Expr(inlvar(addr))
                                ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, ia))
-                               ninit.Append(typecheck(ir.NewAssignStmt(base.Pos, ia, nodAddr(o)), ctxStmt))
+                               ninit.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ia, typecheck.NodAddr(o))))
                                inlvars[addr] = ia
 
                                // When capturing by reference, all occurrence of the captured var
                                // must be substituted with dereference of the temporary address
-                               inlvars[v] = typecheck(ir.NewStarExpr(base.Pos, ia), ctxExpr)
+                               inlvars[v] = typecheck.Expr(ir.NewStarExpr(base.Pos, ia))
                        }
                }
        }
                        // nothing should have moved to the heap yet.
                        base.Fatalf("impossible: %v", ln)
                }
-               inlf := typecheck(inlvar(ln), ctxExpr)
+               inlf := typecheck.Expr(inlvar(ln))
                inlvars[ln] = inlf
                if base.Flag.GenDwarfInl > 0 {
                        if ln.Class_ == ir.PPARAM {
                if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym().Name, "~r") {
                        n := n.(*ir.Name)
                        m = inlvar(n)
-                       m = typecheck(m, ctxExpr)
+                       m = typecheck.Expr(m)
                        inlvars[n] = m
                        delayretvars = false // found a named result parameter
                } else {
                vas = ir.NewAssignStmt(base.Pos, nil, nil)
                vas.X = inlParam(param, vas, inlvars)
                if len(varargs) == 0 {
-                       vas.Y = nodnil()
+                       vas.Y = typecheck.NodNil()
                        vas.Y.SetType(param.Type)
                } else {
                        lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type).(ir.Ntype), nil)
        }
 
        if len(as.Rhs) != 0 {
-               ninit.Append(typecheck(as, ctxStmt))
+               ninit.Append(typecheck.Stmt(as))
        }
 
        if vas != nil {
-               ninit.Append(typecheck(vas, ctxStmt))
+               ninit.Append(typecheck.Stmt(vas))
        }
 
        if !delayretvars {
                for _, n := range retvars {
                        ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n))
                        ras := ir.NewAssignStmt(base.Pos, n, nil)
-                       ninit.Append(typecheck(ras, ctxStmt))
+                       ninit.Append(typecheck.Stmt(ras))
                }
        }
 
-       retlabel := autolabel(".i")
+       retlabel := typecheck.AutoLabel(".i")
 
        inlgen++
 
        lab := ir.NewLabelStmt(base.Pos, retlabel)
        body = append(body, lab)
 
-       typecheckslice(body, ctxStmt)
+       typecheck.Stmts(body)
 
        if base.Flag.GenDwarfInl > 0 {
                for _, v := range inlfvars {
                fmt.Printf("inlvar %+v\n", var_)
        }
 
-       n := NewName(var_.Sym())
+       n := typecheck.NewName(var_.Sym())
        n.SetType(var_.Type())
        n.Class_ = ir.PAUTO
        n.SetUsed(true)
 
 // Synthesize a variable to store the inlined function's results in.
 func retvar(t *types.Field, i int) ir.Node {
-       n := NewName(lookupN("~R", i))
+       n := typecheck.NewName(typecheck.LookupNum("~R", i))
        n.SetType(t.Type)
        n.Class_ = ir.PAUTO
        n.SetUsed(true)
 // Synthesize a variable to store the inlined function's arguments
 // when they come from a multiple return call.
 func argvar(t *types.Type, i int) ir.Node {
-       n := NewName(lookupN("~arg", i))
+       n := typecheck.NewName(typecheck.LookupNum("~arg", i))
        n.SetType(t.Elem())
        n.Class_ = ir.PAUTO
        n.SetUsed(true)
                                }
                        }
 
-                       init = append(init, typecheck(as, ctxStmt))
+                       init = append(init, typecheck.Stmt(as))
                }
                init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
-               typecheckslice(init, ctxStmt)
+               typecheck.Stmts(init)
                return ir.NewBlockStmt(base.Pos, init)
 
        case ir.OGOTO:
                m.SetPos(subst.updatedPos(m.Pos()))
                m.PtrInit().Set(nil)
                p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
-               m.Label = lookup(p)
+               m.Label = typecheck.Lookup(p)
                return m
 
        case ir.OLABEL:
                m.SetPos(subst.updatedPos(m.Pos()))
                m.PtrInit().Set(nil)
                p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
-               m.Label = lookup(p)
+               m.Label = typecheck.Lookup(p)
                return m
        }
 
 
        dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
        dt.SetType(typ)
-       x := typecheck(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel), ctxExpr|ctxCallee)
+       x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
        switch x.Op() {
        case ir.ODOTMETH:
                x := x.(*ir.SelectorExpr)
 
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
        "cmd/compile/internal/ssa"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/bio"
        "cmd/internal/dwarf"
        }
 }
 
-// Target is the package being compiled.
-var Target *ir.Package
-
 // Main parses flags and Go source files specified in the command-line
 // arguments, type-checks the parsed Go package, compiles functions to machine
 // code, and finally writes the compiled package definition to disk.
                return typenamesym(t).Linksym()
        }
 
-       Target = new(ir.Package)
+       typecheck.Target = new(ir.Package)
 
-       NeedFuncSym = makefuncsym
-       NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
-       NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
+       typecheck.NeedFuncSym = makefuncsym
+       typecheck.NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
+       typecheck.NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
 
        base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
 
        types.TypeLinkSym = func(t *types.Type) *obj.LSym {
                return typenamesym(t).Linksym()
        }
-       TypecheckInit()
+       typecheck.Init()
 
        // Parse input.
        base.Timer.Start("fe", "parse")
        recordPackageName()
 
        // Typecheck.
-       TypecheckPackage()
+       typecheck.Package()
 
        // With all user code typechecked, it's now safe to verify unused dot imports.
        checkDotImports()
 
        // Build init task.
        if initTask := fninit(); initTask != nil {
-               exportsym(initTask)
+               typecheck.Export(initTask)
        }
 
        // Inlining
        }
 
        // Devirtualize.
-       for _, n := range Target.Decls {
+       for _, n := range typecheck.Target.Decls {
                if n.Op() == ir.ODCLFUNC {
                        devirtualize(n.(*ir.Func))
                }
        // Large values are also moved off stack in escape analysis;
        // because large values may contain pointers, it must happen early.
        base.Timer.Start("fe", "escapes")
-       escapes(Target.Decls)
+       escapes(typecheck.Target.Decls)
 
        // Collect information for go:nowritebarrierrec
        // checking. This must happen before transformclosure.
        // This needs to happen before walk, because closures must be transformed
        // before walk reaches a call of a closure.
        base.Timer.Start("fe", "xclosures")
-       for _, n := range Target.Decls {
+       for _, n := range typecheck.Target.Decls {
                if n.Op() == ir.ODCLFUNC {
                        n := n.(*ir.Func)
                        if n.OClosure != nil {
        // Don't use range--walk can add functions to Target.Decls.
        base.Timer.Start("be", "compilefuncs")
        fcount := int64(0)
-       for i := 0; i < len(Target.Decls); i++ {
-               n := Target.Decls[i]
+       for i := 0; i < len(typecheck.Target.Decls); i++ {
+               n := typecheck.Target.Decls[i]
                if n.Op() == ir.ODCLFUNC {
                        funccompile(n.(*ir.Func))
                        fcount++
        }
 
        CheckLargeStacks()
-       CheckFuncStack()
+       typecheck.CheckFuncStack()
 
        if len(compilequeue) != 0 {
                base.Fatalf("%d uncompiled functions", len(compilequeue))
 func cgoSymABIs() {
        // The linker expects an ABI0 wrapper for all cgo-exported
        // functions.
-       for _, prag := range Target.CgoPragmas {
+       for _, prag := range typecheck.Target.CgoPragmas {
                switch prag[0] {
                case "cgo_export_static", "cgo_export_dynamic":
                        if symabiRefs == nil {
        return "", false
 }
 
-// loadsys loads the definitions for the low-level runtime functions,
-// so that the compiler can generate calls to them,
-// but does not make them visible to user code.
-func loadsys() {
-       types.Block = 1
-
-       inimport = true
-       typecheckok = true
-
-       typs := runtimeTypes()
-       for _, d := range &runtimeDecls {
-               sym := ir.Pkgs.Runtime.Lookup(d.name)
-               typ := typs[d.typ]
-               switch d.tag {
-               case funcTag:
-                       importfunc(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
-               case varTag:
-                       importvar(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
-               default:
-                       base.Fatalf("unhandled declaration tag %v", d.tag)
-               }
-       }
-
-       typecheckok = false
-       inimport = false
-}
-
 // myheight tracks the local package's height based on packages
 // imported so far.
 var myheight int
                        base.Errorf("import %s: unexpected package format byte: %v", file, c)
                        base.ErrorExit()
                }
-               fingerprint = iimport(importpkg, imp)
+               fingerprint = typecheck.ReadImports(importpkg, imp)
 
        default:
                base.Errorf("no import in %q", path_)
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/objabi"
        "cmd/internal/src"
 func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
        oldScope := p.scope
        p.scope = 0
-       funchdr(fn)
+       typecheck.StartFuncBody(fn)
 
        if block != nil {
                body := p.stmts(block.List)
                fn.Endlineno = base.Pos
        }
 
-       funcbody()
+       typecheck.FinishFuncBody()
        p.scope = oldScope
 }
 
                p.checkUnused(pragma)
        }
 
-       Target.Decls = append(Target.Decls, p.decls(p.file.DeclList)...)
+       typecheck.Target.Decls = append(typecheck.Target.Decls, p.decls(p.file.DeclList)...)
 
        base.Pos = src.NoXPos
        clearImports()
                        p.errorAt(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
                        continue
                }
-               n := ir.AsNode(lookup(l.local).Def)
+               n := ir.AsNode(typecheck.Lookup(l.local).Def)
                if n == nil || n.Op() != ir.ONAME {
                        // TODO(mdempsky): Change to p.errorAt before Go 1.17 release.
                        // base.WarnfAt(p.makeXPos(l.pos), "//go:linkname must refer to declared function or variable (will be an error in Go 1.17)")
                }
                n.Sym().Linkname = l.remote
        }
-       Target.CgoPragmas = append(Target.CgoPragmas, p.pragcgobuf...)
+       typecheck.Target.CgoPragmas = append(typecheck.Target.CgoPragmas, p.pragcgobuf...)
 }
 
 func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) {
        }
 
        if !ipkg.Direct {
-               Target.Imports = append(Target.Imports, ipkg)
+               typecheck.Target.Imports = append(typecheck.Target.Imports, ipkg)
        }
        ipkg.Direct = true
 
        if imp.LocalPkgName != nil {
                my = p.name(imp.LocalPkgName)
        } else {
-               my = lookup(ipkg.Name)
+               my = typecheck.Lookup(ipkg.Name)
        }
 
        pack := ir.NewPkgName(p.pos(imp), my, ipkg)
                return
        }
        if my.Def != nil {
-               redeclare(pack.Pos(), my, "as imported package name")
+               typecheck.Redeclared(pack.Pos(), my, "as imported package name")
        }
        my.Def = pack
        my.Lastlineno = pack.Pos()
        }
 
        p.setlineno(decl)
-       return variter(names, typ, exprs)
+       return typecheck.DeclVars(names, typ, exprs)
 }
 
 // constState tracks state between constant specifiers within a
                if decl.Values == nil {
                        v = ir.DeepCopy(n.Pos(), v)
                }
-               declare(n, dclcontext)
+               typecheck.Declare(n, typecheck.DeclContext)
 
                n.Ntype = typ
                n.Defn = v
 
 func (p *noder) typeDecl(decl *syntax.TypeDecl) ir.Node {
        n := p.declName(ir.OTYPE, decl.Name)
-       declare(n, dclcontext)
+       typecheck.Declare(n, typecheck.DeclContext)
 
        // decl.Type may be nil but in that case we got a syntax error during parsing
        typ := p.typeExprOrNil(decl.Type)
                        if len(t.Params) > 0 || len(t.Results) > 0 {
                                base.ErrorfAt(f.Pos(), "func init must have no arguments and no return values")
                        }
-                       Target.Inits = append(Target.Inits, f)
+                       typecheck.Target.Inits = append(typecheck.Target.Inits, f)
                }
 
                if types.LocalPkg.Name == "main" && name.Name == "main" {
        }
 
        if fun.Recv == nil {
-               declare(f.Nname, ir.PFUNC)
+               typecheck.Declare(f.Nname, ir.PFUNC)
        }
 
        p.funcBody(f, fun.Body)
                        pos, op := p.pos(expr), p.unOp(expr.Op)
                        switch op {
                        case ir.OADDR:
-                               return nodAddrAt(pos, x)
+                               return typecheck.NodAddrAt(pos, x)
                        case ir.ODEREF:
                                return ir.NewStarExpr(pos, x)
                        }
        }
 
        sym := p.packname(typ)
-       n := ir.NewField(p.pos(typ), lookup(sym.Name), importName(sym).(ir.Ntype), nil)
+       n := ir.NewField(p.pos(typ), typecheck.Lookup(sym.Name), importName(sym).(ir.Ntype), nil)
        n.Embedded = true
 
        if isStar {
                }
 
                newOrErr = true
-               n := NewName(sym)
-               declare(n, dclcontext)
+               n := typecheck.NewName(sym)
+               typecheck.Declare(n, typecheck.DeclContext)
                n.Defn = defn
                defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
                res[i] = n
                        n.List.Set(p.exprList(clause.Cases))
                }
                if tswitch != nil && tswitch.Tag != nil {
-                       nn := NewName(tswitch.Tag.Sym())
-                       declare(nn, dclcontext)
+                       nn := typecheck.NewName(tswitch.Tag.Sym())
+                       typecheck.Declare(nn, typecheck.DeclContext)
                        n.Vars = []ir.Node{nn}
                        // keep track of the instances for reporting unused
                        nn.Defn = tswitch
 }
 
 func (p *noder) name(name *syntax.Name) *types.Sym {
-       return lookup(name.Value)
+       return typecheck.Lookup(name.Value)
 }
 
 func (p *noder) mkname(name *syntax.Name) ir.Node {
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/bio"
        "cmd/internal/obj"
 }
 
 func dumpdata() {
-       numExterns := len(Target.Externs)
-       numDecls := len(Target.Decls)
+       numExterns := len(typecheck.Target.Externs)
+       numDecls := len(typecheck.Target.Decls)
 
-       dumpglobls(Target.Externs)
+       dumpglobls(typecheck.Target.Externs)
        dumpfuncsyms()
        addptabs()
-       numExports := len(Target.Exports)
-       addsignats(Target.Externs)
+       numExports := len(typecheck.Target.Exports)
+       addsignats(typecheck.Target.Externs)
        dumpsignats()
        dumptabs()
        numPTabs, numITabs := CountTabs()
        // In the typical case, we loop 0 or 1 times.
        // It was not until issue 24761 that we found any code that required a loop at all.
        for {
-               for i := numDecls; i < len(Target.Decls); i++ {
-                       n := Target.Decls[i]
+               for i := numDecls; i < len(typecheck.Target.Decls); i++ {
+                       n := typecheck.Target.Decls[i]
                        if n.Op() == ir.ODCLFUNC {
                                funccompile(n.(*ir.Func))
                        }
                }
-               numDecls = len(Target.Decls)
+               numDecls = len(typecheck.Target.Decls)
                compileFunctions()
                dumpsignats()
-               if numDecls == len(Target.Decls) {
+               if numDecls == len(typecheck.Target.Decls) {
                        break
                }
        }
 
        // Dump extra globals.
-       dumpglobls(Target.Externs[numExterns:])
+       dumpglobls(typecheck.Target.Externs[numExterns:])
 
        if zerosize > 0 {
                zero := ir.Pkgs.Map.Lookup("zero")
 
        addGCLocals()
 
-       if numExports != len(Target.Exports) {
+       if numExports != len(typecheck.Target.Exports) {
                base.Fatalf("Target.Exports changed after compile functions loop")
        }
        newNumPTabs, newNumITabs := CountTabs()
 func dumpLinkerObj(bout *bio.Writer) {
        printObjHeader(bout)
 
-       if len(Target.CgoPragmas) != 0 {
+       if len(typecheck.Target.CgoPragmas) != 0 {
                // write empty export section; must be before cgo section
                fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
                fmt.Fprintf(bout, "\n$$  // cgo\n")
-               if err := json.NewEncoder(bout).Encode(Target.CgoPragmas); err != nil {
+               if err := json.NewEncoder(bout).Encode(typecheck.Target.CgoPragmas); err != nil {
                        base.Fatalf("serializing pragcgobuf: %v", err)
                }
                fmt.Fprintf(bout, "\n$$\n\n")
        if !base.Ctxt.Flag_dynlink || types.LocalPkg.Name != "main" {
                return
        }
-       for _, exportn := range Target.Exports {
+       for _, exportn := range typecheck.Target.Exports {
                s := exportn.Sym()
                nn := ir.AsNode(s.Def)
                if nn == nil {
        slicedataGen++
        symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
        sym := types.LocalPkg.Lookup(symname)
-       symnode := NewName(sym)
+       symnode := typecheck.NewName(sym)
        sym.Def = symnode
 
        lsym := sym.Linksym()
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
        "fmt"
 
 // append typechecks stmt and appends it to out.
 func (o *Order) append(stmt ir.Node) {
-       o.out = append(o.out, typecheck(stmt, ctxStmt))
+       o.out = append(o.out, typecheck.Stmt(stmt))
 }
 
 // newTemp allocates a new temporary with the given type,
                }
        }
        if v == nil {
-               v = temp(t)
+               v = typecheck.Temp(t)
        }
        if clear {
                o.append(ir.NewAssignStmt(base.Pos, v, nil))
                }
                a := ir.SepCopy(n).(*ir.UnaryExpr)
                a.X = l
-               return typecheck(a, ctxExpr)
+               return typecheck.Expr(a)
        }
 
        return o.copyExpr(n)
                }
                a := ir.SepCopy(n).(*ir.UnaryExpr)
                a.X = l
-               return typecheck(a, ctxExpr)
+               return typecheck.Expr(a)
 
        case ir.ODOT:
                n := n.(*ir.SelectorExpr)
                }
                a := ir.SepCopy(n).(*ir.SelectorExpr)
                a.X = l
-               return typecheck(a, ctxExpr)
+               return typecheck.Expr(a)
 
        case ir.ODOTPTR:
                n := n.(*ir.SelectorExpr)
                }
                a := ir.SepCopy(n).(*ir.SelectorExpr)
                a.X = l
-               return typecheck(a, ctxExpr)
+               return typecheck.Expr(a)
 
        case ir.ODEREF:
                n := n.(*ir.StarExpr)
                }
                a := ir.SepCopy(n).(*ir.StarExpr)
                a.X = l
-               return typecheck(a, ctxExpr)
+               return typecheck.Expr(a)
 
        case ir.OINDEX, ir.OINDEXMAP:
                n := n.(*ir.IndexExpr)
                a := ir.SepCopy(n).(*ir.IndexExpr)
                a.X = l
                a.Index = r
-               return typecheck(a, ctxExpr)
+               return typecheck.Expr(a)
 
        default:
                base.Fatalf("order.safeExpr %v", n.Op())
 func (o *Order) addrTemp(n ir.Node) ir.Node {
        if n.Op() == ir.OLITERAL || n.Op() == ir.ONIL {
                // TODO: expand this to all static composite literal nodes?
-               n = defaultlit(n, nil)
+               n = typecheck.DefaultLit(n, nil)
                types.CalcSize(n.Type())
                vstat := readonlystaticname(n.Type())
                var s InitSchedule
                if s.out != nil {
                        base.Fatalf("staticassign of const generated code: %+v", n)
                }
-               vstat = typecheck(vstat, ctxExpr).(*ir.Name)
+               vstat = typecheck.Expr(vstat).(*ir.Name)
                return vstat
        }
        if isaddrokay(n) {
        var out []ir.Node
        for i := len(o.temp) - 1; i >= int(mark); i-- {
                n := o.temp[i]
-               out = append(out, typecheck(ir.NewUnaryExpr(base.Pos, ir.OVARKILL, n), ctxStmt))
+               out = append(out, typecheck.Stmt(ir.NewUnaryExpr(base.Pos, ir.OVARKILL, n)))
        }
        return out
 }
        mk.Cap = cp.Y
        // Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
        mk.SetBounded(mk.Len.Op() == ir.OLEN && ir.SameSafeExpr(mk.Len.(*ir.UnaryExpr).X, cp.Y))
-       as.Y = typecheck(mk, ctxExpr)
+       as.Y = typecheck.Expr(mk)
        s[1] = nil // remove separate copy call
 }
 
        }
 
        n := nn.(*ir.CallExpr)
-       fixVariadicCall(n)
+       typecheck.FixVariadicCall(n)
        n.X = o.expr(n.X, nil)
        o.exprList(n.Args)
 
                                x := o.copyExpr(arg.X)
                                arg.X = x
                                x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
-                               n.Body.Append(typecheck(ir.NewUnaryExpr(base.Pos, ir.OVARLIVE, x), ctxStmt))
+                               n.Body.Append(typecheck.Stmt(ir.NewUnaryExpr(base.Pos, ir.OVARLIVE, x)))
                        }
                }
        }
                                t := o.newTemp(m.Type(), false)
                                n.Lhs[i] = t
                                a := ir.NewAssignStmt(base.Pos, m, t)
-                               post = append(post, typecheck(a, ctxStmt))
+                               post = append(post, typecheck.Stmt(a))
                        }
                }
 
                                l2.Assigned = false
                        }
                        l2 = o.copyExpr(l2)
-                       r := o.expr(typecheck(ir.NewBinaryExpr(n.Pos(), n.AsOp, l2, n.Y), ctxExpr), nil)
-                       as := typecheck(ir.NewAssignStmt(n.Pos(), l1, r), ctxStmt)
+                       r := o.expr(typecheck.Expr(ir.NewBinaryExpr(n.Pos(), n.AsOp, l2, n.Y)), nil)
+                       as := typecheck.Stmt(ir.NewAssignStmt(n.Pos(), l1, r))
                        o.mapAssign(as)
                        o.cleanTemp(t)
                        return
                        if r.Type().IsString() && r.Type() != types.Types[types.TSTRING] {
                                r = ir.NewConvExpr(base.Pos, ir.OCONV, nil, r)
                                r.SetType(types.Types[types.TSTRING])
-                               r = typecheck(r, ctxExpr)
+                               r = typecheck.Expr(r)
                        }
 
                        n.X = o.copyExpr(r)
                                                if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).X == n {
                                                        init = init[1:]
                                                }
-                                               dcl := typecheck(ir.NewDecl(base.Pos, ir.ODCL, n), ctxStmt)
+                                               dcl := typecheck.Stmt(ir.NewDecl(base.Pos, ir.ODCL, n))
                                                ncas.PtrInit().Append(dcl)
                                        }
                                        tmp := o.newTemp(t, t.HasPointers())
-                                       as := typecheck(ir.NewAssignStmt(base.Pos, n, conv(tmp, n.Type())), ctxStmt)
+                                       as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, n, typecheck.Conv(tmp, n.Type())))
                                        ncas.PtrInit().Append(as)
                                        r.Lhs[i] = tmp
                                }
 
                // Evaluate left-hand side.
                lhs := o.expr(n.X, nil)
-               o.out = append(o.out, typecheck(ir.NewAssignStmt(base.Pos, r, lhs), ctxStmt))
+               o.out = append(o.out, typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, lhs)))
 
                // Evaluate right-hand side, save generated code.
                saveout := o.out
                t := o.markTemp()
                o.edge()
                rhs := o.expr(n.Y, nil)
-               o.out = append(o.out, typecheck(ir.NewAssignStmt(base.Pos, r, rhs), ctxStmt))
+               o.out = append(o.out, typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, rhs)))
                o.cleanTemp(t)
                gen := o.out
                o.out = saveout
        case ir.OCLOSURE:
                n := n.(*ir.ClosureExpr)
                if n.Transient() && len(n.Func.ClosureVars) > 0 {
-                       n.Prealloc = o.newTemp(closureType(n), false)
+                       n.Prealloc = o.newTemp(typecheck.ClosureType(n), false)
                }
                return n
 
                n := n.(*ir.CallPartExpr)
                n.X = o.expr(n.X, nil)
                if n.Transient() {
-                       t := partialCallType(n)
+                       t := typecheck.PartialCallType(n)
                        n.Prealloc = o.newTemp(t, false)
                }
                return n
                // Emit the creation of the map (with all its static entries).
                m := o.newTemp(n.Type(), false)
                as := ir.NewAssignStmt(base.Pos, m, n)
-               typecheck(as, ctxStmt)
+               typecheck.Stmt(as)
                o.stmt(as)
 
                // Emit eval+insert of dynamic entries, one at a time.
                for _, r := range dynamics {
                        as := ir.NewAssignStmt(base.Pos, ir.NewIndexExpr(base.Pos, m, r.Key), r.Value)
-                       typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
+                       typecheck.Stmt(as) // Note: this converts the OINDEX to an OINDEXMAP
                        o.stmt(as)
                }
                return m
        as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
        as.Lhs.Set(left)
        as.Rhs.Set(tmplist)
-       o.stmt(typecheck(as, ctxStmt))
+       o.stmt(typecheck.Stmt(as))
 }
 
 // okAs2 orders OAS2XXX with ok.
 
        if tmp1 != nil {
                r := ir.NewAssignStmt(base.Pos, n.Lhs[0], tmp1)
-               o.mapAssign(typecheck(r, ctxStmt))
+               o.mapAssign(typecheck.Stmt(r))
                n.Lhs[0] = tmp1
        }
        if tmp2 != nil {
-               r := ir.NewAssignStmt(base.Pos, n.Lhs[1], conv(tmp2, n.Lhs[1].Type()))
-               o.mapAssign(typecheck(r, ctxStmt))
+               r := ir.NewAssignStmt(base.Pos, n.Lhs[1], typecheck.Conv(tmp2, n.Lhs[1].Type()))
+               o.mapAssign(typecheck.Stmt(r))
                n.Lhs[1] = tmp2
        }
 }
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/ssa"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/dwarf"
        "cmd/internal/obj"
        }
 
        if f.Config.NeedsFpScratch && scratchUsed {
-               s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[types.TUINT64])
+               s.scratchFpMem = typecheck.TempAt(src.NoXPos, s.curfn, types.Types[types.TUINT64])
        }
 
        sort.Sort(byStackVar(fn.Dcl))
                return
        }
 
-       dclcontext = ir.PAUTO
+       typecheck.DeclContext = ir.PAUTO
        ir.CurFunc = fn
        compile(fn)
        ir.CurFunc = nil
-       dclcontext = ir.PEXTERN
+       typecheck.DeclContext = ir.PEXTERN
 }
 
 func compile(fn *ir.Func) {
 
 
 import (
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
        "reflect"
                if s == nil {
                        s = &types.Sym{Name: "."}
                }
-               n := NewName(s)
+               n := typecheck.NewName(s)
                n.SetType(t)
                n.SetFrameOffset(xoffset)
                n.Class_ = cl
 
 func TestStackvarSort(t *testing.T) {
        nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
-               n := NewName(s)
+               n := typecheck.NewName(s)
                n.SetType(t)
                n.SetFrameOffset(xoffset)
                n.Class_ = cl
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/sys"
        "unicode/utf8"
 )
 
-// range
-func typecheckrange(n *ir.RangeStmt) {
-       // Typechecking order is important here:
-       // 0. first typecheck range expression (slice/map/chan),
-       //      it is evaluated only once and so logically it is not part of the loop.
-       // 1. typecheck produced values,
-       //      this part can declare new vars and so it must be typechecked before body,
-       //      because body can contain a closure that captures the vars.
-       // 2. decldepth++ to denote loop body.
-       // 3. typecheck body.
-       // 4. decldepth--.
-       typecheckrangeExpr(n)
-
-       // second half of dance, the first half being typecheckrangeExpr
-       n.SetTypecheck(1)
-       ls := n.Vars
-       for i1, n1 := range ls {
-               if n1.Typecheck() == 0 {
-                       ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
-               }
-       }
-
-       decldepth++
-       typecheckslice(n.Body, ctxStmt)
-       decldepth--
-}
-
-func typecheckrangeExpr(n *ir.RangeStmt) {
-       n.X = typecheck(n.X, ctxExpr)
-
-       t := n.X.Type()
-       if t == nil {
-               return
-       }
-       // delicate little dance.  see typecheckas2
-       ls := n.Vars
-       for i1, n1 := range ls {
-               if !ir.DeclaredBy(n1, n) {
-                       ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
-               }
-       }
-
-       if t.IsPtr() && t.Elem().IsArray() {
-               t = t.Elem()
-       }
-       n.SetType(t)
-
-       var t1, t2 *types.Type
-       toomany := false
-       switch t.Kind() {
-       default:
-               base.ErrorfAt(n.Pos(), "cannot range over %L", n.X)
-               return
-
-       case types.TARRAY, types.TSLICE:
-               t1 = types.Types[types.TINT]
-               t2 = t.Elem()
-
-       case types.TMAP:
-               t1 = t.Key()
-               t2 = t.Elem()
-
-       case types.TCHAN:
-               if !t.ChanDir().CanRecv() {
-                       base.ErrorfAt(n.Pos(), "invalid operation: range %v (receive from send-only type %v)", n.X, n.X.Type())
-                       return
-               }
-
-               t1 = t.Elem()
-               t2 = nil
-               if len(n.Vars) == 2 {
-                       toomany = true
-               }
-
-       case types.TSTRING:
-               t1 = types.Types[types.TINT]
-               t2 = types.RuneType
-       }
-
-       if len(n.Vars) > 2 || toomany {
-               base.ErrorfAt(n.Pos(), "too many variables in range")
-       }
-
-       var v1, v2 ir.Node
-       if len(n.Vars) != 0 {
-               v1 = n.Vars[0]
-       }
-       if len(n.Vars) > 1 {
-               v2 = n.Vars[1]
-       }
-
-       // this is not only an optimization but also a requirement in the spec.
-       // "if the second iteration variable is the blank identifier, the range
-       // clause is equivalent to the same clause with only the first variable
-       // present."
-       if ir.IsBlank(v2) {
-               if v1 != nil {
-                       n.Vars = []ir.Node{v1}
-               }
-               v2 = nil
-       }
-
-       if v1 != nil {
-               if ir.DeclaredBy(v1, n) {
-                       v1.SetType(t1)
-               } else if v1.Type() != nil {
-                       if op, why := assignop(t1, v1.Type()); op == ir.OXXX {
-                               base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t1, v1, why)
-                       }
-               }
-               checkassign(n, v1)
-       }
-
-       if v2 != nil {
-               if ir.DeclaredBy(v2, n) {
-                       v2.SetType(t2)
-               } else if v2.Type() != nil {
-                       if op, why := assignop(t2, v2.Type()); op == ir.OXXX {
-                               base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t2, v2, why)
-                       }
-               }
-               checkassign(n, v2)
-       }
-}
-
 func cheapComputableIndex(width int64) bool {
        switch thearch.LinkArch.Family {
        // MIPS does not have R+R addressing
                // order.stmt arranged for a copy of the array/slice variable if needed.
                ha := a
 
-               hv1 := temp(types.Types[types.TINT])
-               hn := temp(types.Types[types.TINT])
+               hv1 := typecheck.Temp(types.Types[types.TINT])
+               hn := typecheck.Temp(types.Types[types.TINT])
 
                init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
                init = append(init, ir.NewAssignStmt(base.Pos, hn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ha)))
                ifGuard.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn)
                nfor.SetOp(ir.OFORUNTIL)
 
-               hp := temp(types.NewPtr(nrange.Type().Elem()))
+               hp := typecheck.Temp(types.NewPtr(nrange.Type().Elem()))
                tmp := ir.NewIndexExpr(base.Pos, ha, ir.NewInt(0))
                tmp.SetBounded(true)
-               init = append(init, ir.NewAssignStmt(base.Pos, hp, nodAddr(tmp)))
+               init = append(init, ir.NewAssignStmt(base.Pos, hp, typecheck.NodAddr(tmp)))
 
                // Use OAS2 to correctly handle assignments
                // of the form "v1, a[v1] := range".
                // advancing the pointer is safe and won't go past the
                // end of the allocation.
                as := ir.NewAssignStmt(base.Pos, hp, addptr(hp, t.Elem().Width))
-               nfor.Late = []ir.Node{typecheck(as, ctxStmt)}
+               nfor.Late = []ir.Node{typecheck.Stmt(as)}
 
        case types.TMAP:
                // order.stmt allocated the iterator for us.
                keysym := th.Field(0).Sym  // depends on layout of iterator struct.  See reflect.go:hiter
                elemsym := th.Field(1).Sym // ditto
 
-               fn := syslook("mapiterinit")
+               fn := typecheck.LookupRuntime("mapiterinit")
 
-               fn = substArgTypes(fn, t.Key(), t.Elem(), th)
-               init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nodAddr(hit)))
-               nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), nodnil())
+               fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), th)
+               init = append(init, mkcall1(fn, nil, nil, typename(t), ha, typecheck.NodAddr(hit)))
+               nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil())
 
-               fn = syslook("mapiternext")
-               fn = substArgTypes(fn, th)
-               nfor.Post = mkcall1(fn, nil, nil, nodAddr(hit))
+               fn = typecheck.LookupRuntime("mapiternext")
+               fn = typecheck.SubstArgTypes(fn, th)
+               nfor.Post = mkcall1(fn, nil, nil, typecheck.NodAddr(hit))
 
                key := ir.NewStarExpr(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym))
                if v1 == nil {
                // order.stmt arranged for a copy of the channel variable.
                ha := a
 
-               hv1 := temp(t.Elem())
+               hv1 := typecheck.Temp(t.Elem())
                hv1.SetTypecheck(1)
                if t.Elem().HasPointers() {
                        init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
                }
-               hb := temp(types.Types[types.TBOOL])
+               hb := typecheck.Temp(types.Types[types.TBOOL])
 
                nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, hb, ir.NewBool(false))
                a := ir.NewAssignListStmt(base.Pos, ir.OAS2RECV, nil, nil)
                // order.stmt arranged for a copy of the string variable.
                ha := a
 
-               hv1 := temp(types.Types[types.TINT])
-               hv1t := temp(types.Types[types.TINT])
-               hv2 := temp(types.RuneType)
+               hv1 := typecheck.Temp(types.Types[types.TINT])
+               hv1t := typecheck.Temp(types.Types[types.TINT])
+               hv2 := typecheck.Temp(types.RuneType)
 
                // hv1 := 0
                init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
                // hv2 := rune(ha[hv1])
                nind := ir.NewIndexExpr(base.Pos, ha, hv1)
                nind.SetBounded(true)
-               body = append(body, ir.NewAssignStmt(base.Pos, hv2, conv(nind, types.RuneType)))
+               body = append(body, ir.NewAssignStmt(base.Pos, hv2, typecheck.Conv(nind, types.RuneType)))
 
                // if hv2 < utf8.RuneSelf
                nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
 
                // hv2, hv1 = decoderune(ha, hv1)
                eif.Lhs = []ir.Node{hv2, hv1}
-               fn := syslook("decoderune")
+               fn := typecheck.LookupRuntime("decoderune")
                eif.Rhs = []ir.Node{mkcall1(fn, fn.Type().Results(), nil, ha, hv1)}
 
                body = append(body, nif)
                }
        }
 
-       typecheckslice(init, ctxStmt)
+       typecheck.Stmts(init)
 
        if ifGuard != nil {
                ifGuard.PtrInit().Append(init...)
-               ifGuard = typecheck(ifGuard, ctxStmt).(*ir.IfStmt)
+               ifGuard = typecheck.Stmt(ifGuard).(*ir.IfStmt)
        } else {
                nfor.PtrInit().Append(init...)
        }
 
-       typecheckslice(nfor.Cond.Init(), ctxStmt)
+       typecheck.Stmts(nfor.Cond.Init())
 
-       nfor.Cond = typecheck(nfor.Cond, ctxExpr)
-       nfor.Cond = defaultlit(nfor.Cond, nil)
-       nfor.Post = typecheck(nfor.Post, ctxStmt)
-       typecheckslice(body, ctxStmt)
+       nfor.Cond = typecheck.Expr(nfor.Cond)
+       nfor.Cond = typecheck.DefaultLit(nfor.Cond, nil)
+       nfor.Post = typecheck.Stmt(nfor.Post)
+       typecheck.Stmts(body)
        nfor.Body.Append(body...)
        nfor.Body.Append(nrange.Body...)
 
        t := m.Type()
 
        // instantiate mapclear(typ *type, hmap map[any]any)
-       fn := syslook("mapclear")
-       fn = substArgTypes(fn, t.Key(), t.Elem())
+       fn := typecheck.LookupRuntime("mapclear")
+       fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
        n := mkcall1(fn, nil, nil, typename(t), m)
-       return walkstmt(typecheck(n, ctxStmt))
+       return walkstmt(typecheck.Stmt(n))
 }
 
 // Lower n into runtime·memclr if possible, for
        n.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(0))
 
        // hp = &a[0]
-       hp := temp(types.Types[types.TUNSAFEPTR])
+       hp := typecheck.Temp(types.Types[types.TUNSAFEPTR])
 
        ix := ir.NewIndexExpr(base.Pos, a, ir.NewInt(0))
        ix.SetBounded(true)
-       addr := convnop(nodAddr(ix), types.Types[types.TUNSAFEPTR])
+       addr := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
        n.Body.Append(ir.NewAssignStmt(base.Pos, hp, addr))
 
        // hn = len(a) * sizeof(elem(a))
-       hn := temp(types.Types[types.TUINTPTR])
-       mul := conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(elemsize)), types.Types[types.TUINTPTR])
+       hn := typecheck.Temp(types.Types[types.TUINTPTR])
+       mul := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(elemsize)), types.Types[types.TUINTPTR])
        n.Body.Append(ir.NewAssignStmt(base.Pos, hn, mul))
 
        var fn ir.Node
 
        n.Body.Append(v1)
 
-       n.Cond = typecheck(n.Cond, ctxExpr)
-       n.Cond = defaultlit(n.Cond, nil)
-       typecheckslice(n.Body, ctxStmt)
+       n.Cond = typecheck.Expr(n.Cond)
+       n.Cond = typecheck.DefaultLit(n.Cond, nil)
+       typecheck.Stmts(n.Body)
        return walkstmt(n)
 }
 
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/gcprog"
        "cmd/internal/obj"
        return s
 }
 
-// f is method type, with receiver.
-// return function type, receiver as first argument (or not).
-func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
-       inLen := f.Params().Fields().Len()
-       if receiver != nil {
-               inLen++
-       }
-       in := make([]*ir.Field, 0, inLen)
-
-       if receiver != nil {
-               d := ir.NewField(base.Pos, nil, nil, receiver)
-               in = append(in, d)
-       }
-
-       for _, t := range f.Params().Fields().Slice() {
-               d := ir.NewField(base.Pos, nil, nil, t.Type)
-               d.IsDDD = t.IsDDD()
-               in = append(in, d)
-       }
-
-       outLen := f.Results().Fields().Len()
-       out := make([]*ir.Field, 0, outLen)
-       for _, t := range f.Results().Fields().Slice() {
-               d := ir.NewField(base.Pos, nil, nil, t.Type)
-               out = append(out, d)
-       }
-
-       return functype(nil, in, out)
-}
-
 // methods returns the methods of the non-interface type t, sorted by name.
 // Generates stub functions as needed.
 func methods(t *types.Type) []*Sig {
        if mt == nil {
                return nil
        }
-       expandmeth(mt)
+       typecheck.CalcMethods(mt)
 
        // type stored in interface word
        it := t
                        name:  method,
                        isym:  ir.MethodSym(it, method),
                        tsym:  ir.MethodSym(t, method),
-                       type_: methodfunc(f.Type, t),
-                       mtype: methodfunc(f.Type, nil),
+                       type_: typecheck.NewMethodType(f.Type, t),
+                       mtype: typecheck.NewMethodType(f.Type, nil),
                }
                ms = append(ms, sig)
 
                sig := &Sig{
                        name:  f.Sym,
                        mtype: f.Type,
-                       type_: methodfunc(f.Type, nil),
+                       type_: typecheck.NewMethodType(f.Type, nil),
                }
                methods = append(methods, sig)
 
                s.Def = n
        }
 
-       n := nodAddr(ir.AsNode(s.Def))
+       n := typecheck.NodAddr(ir.AsNode(s.Def))
        n.SetType(types.NewPtr(s.Def.Type()))
        n.SetTypecheck(1)
        return n
        }
        s := ir.Pkgs.Itab.Lookup(t.ShortString() + "," + itype.ShortString())
        if s.Def == nil {
-               n := NewName(s)
+               n := typecheck.NewName(s)
                n.SetType(types.Types[types.TUINT8])
                n.Class_ = ir.PEXTERN
                n.SetTypecheck(1)
                itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
        }
 
-       n := nodAddr(ir.AsNode(s.Def))
+       n := typecheck.NodAddr(ir.AsNode(s.Def))
        n.SetType(types.NewPtr(s.Def.Type()))
        n.SetTypecheck(1)
        return n
        if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc
                // named types from other files are defined only by those files
                if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg {
-                       if i := BaseTypeIndex(t); i >= 0 {
+                       if i := typecheck.BaseTypeIndex(t); i >= 0 {
                                lsym.Pkg = tbase.Sym().Pkg.Prefix
                                lsym.SymIdx = int32(i)
                                lsym.Set(obj.AttrIndexed, true)
                // The latter is the type of an auto-generated wrapper.
                dtypesym(types.NewPtr(types.ErrorType))
 
-               dtypesym(functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])}))
+               dtypesym(typecheck.NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])}))
 
                // add paths for runtime and main, which 6l imports implicitly.
                dimportpath(ir.Pkgs.Runtime)
        }
        s := ir.Pkgs.Map.Lookup("zero")
        if s.Def == nil {
-               x := NewName(s)
+               x := typecheck.NewName(s)
                x.SetType(types.Types[types.TUINT8])
                x.Class_ = ir.PEXTERN
                x.SetTypecheck(1)
                s.Def = x
        }
-       z := nodAddr(ir.AsNode(s.Def))
+       z := typecheck.NodAddr(ir.AsNode(s.Def))
        z.SetType(types.NewPtr(types.Types[types.TUINT8]))
        z.SetTypecheck(1)
        return z
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
 )
 
-// select
-func typecheckselect(sel *ir.SelectStmt) {
-       var def ir.Node
-       lno := ir.SetPos(sel)
-       typecheckslice(sel.Init(), ctxStmt)
-       for _, ncase := range sel.Cases {
-               ncase := ncase.(*ir.CaseStmt)
-
-               if len(ncase.List) == 0 {
-                       // default
-                       if def != nil {
-                               base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
-                       } else {
-                               def = ncase
-                       }
-               } else if len(ncase.List) > 1 {
-                       base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
-               } else {
-                       ncase.List[0] = typecheck(ncase.List[0], ctxStmt)
-                       n := ncase.List[0]
-                       ncase.Comm = n
-                       ncase.List.Set(nil)
-                       oselrecv2 := func(dst, recv ir.Node, colas bool) {
-                               n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil)
-                               n.Lhs = []ir.Node{dst, ir.BlankNode}
-                               n.Rhs = []ir.Node{recv}
-                               n.Def = colas
-                               n.SetTypecheck(1)
-                               ncase.Comm = n
-                       }
-                       switch n.Op() {
-                       default:
-                               pos := n.Pos()
-                               if n.Op() == ir.ONAME {
-                                       // We don't have the right position for ONAME nodes (see #15459 and
-                                       // others). Using ncase.Pos for now as it will provide the correct
-                                       // line number (assuming the expression follows the "case" keyword
-                                       // on the same line). This matches the approach before 1.10.
-                                       pos = ncase.Pos()
-                               }
-                               base.ErrorfAt(pos, "select case must be receive, send or assign recv")
-
-                       case ir.OAS:
-                               // convert x = <-c into x, _ = <-c
-                               // remove implicit conversions; the eventual assignment
-                               // will reintroduce them.
-                               n := n.(*ir.AssignStmt)
-                               if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
-                                       r := r.(*ir.ConvExpr)
-                                       if r.Implicit() {
-                                               n.Y = r.X
-                                       }
-                               }
-                               if n.Y.Op() != ir.ORECV {
-                                       base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
-                                       break
-                               }
-                               oselrecv2(n.X, n.Y, n.Def)
-
-                       case ir.OAS2RECV:
-                               n := n.(*ir.AssignListStmt)
-                               if n.Rhs[0].Op() != ir.ORECV {
-                                       base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
-                                       break
-                               }
-                               n.SetOp(ir.OSELRECV2)
-
-                       case ir.ORECV:
-                               // convert <-c into _, _ = <-c
-                               n := n.(*ir.UnaryExpr)
-                               oselrecv2(ir.BlankNode, n, false)
-
-                       case ir.OSEND:
-                               break
-                       }
-               }
-
-               typecheckslice(ncase.Body, ctxStmt)
-       }
-
-       base.Pos = lno
-}
-
 func walkselect(sel *ir.SelectStmt) {
        lno := ir.SetPos(sel)
        if len(sel.Compiled) != 0 {
                switch n.Op() {
                case ir.OSEND:
                        n := n.(*ir.SendStmt)
-                       n.Value = nodAddr(n.Value)
-                       n.Value = typecheck(n.Value, ctxExpr)
+                       n.Value = typecheck.NodAddr(n.Value)
+                       n.Value = typecheck.Expr(n.Value)
 
                case ir.OSELRECV2:
                        n := n.(*ir.AssignListStmt)
                        if !ir.IsBlank(n.Lhs[0]) {
-                               n.Lhs[0] = nodAddr(n.Lhs[0])
-                               n.Lhs[0] = typecheck(n.Lhs[0], ctxExpr)
+                               n.Lhs[0] = typecheck.NodAddr(n.Lhs[0])
+                               n.Lhs[0] = typecheck.Expr(n.Lhs[0])
                        }
                }
        }
                        ch := recv.X
                        elem := n.Lhs[0]
                        if ir.IsBlank(elem) {
-                               elem = nodnil()
+                               elem = typecheck.NodNil()
                        }
                        if ir.IsBlank(n.Lhs[1]) {
                                // if selectnbrecv(&v, c) { body } else { default body }
                        } else {
                                // TODO(cuonglm): make this use selectnbrecv()
                                // if selectnbrecv2(&v, &received, c) { body } else { default body }
-                               receivedp := typecheck(nodAddr(n.Lhs[1]), ctxExpr)
+                               receivedp := typecheck.Expr(typecheck.NodAddr(n.Lhs[1]))
                                call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
                        }
                }
 
-               r.Cond = typecheck(call, ctxExpr)
+               r.Cond = typecheck.Expr(call)
                r.Body.Set(cas.Body)
                r.Else.Set(append(dflt.Init(), dflt.Body...))
                return []ir.Node{r, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)}
 
        // generate sel-struct
        base.Pos = sellineno
-       selv := temp(types.NewArray(scasetype(), int64(ncas)))
-       init = append(init, typecheck(ir.NewAssignStmt(base.Pos, selv, nil), ctxStmt))
+       selv := typecheck.Temp(types.NewArray(scasetype(), int64(ncas)))
+       init = append(init, typecheck.Stmt(ir.NewAssignStmt(base.Pos, selv, nil)))
 
        // No initialization for order; runtime.selectgo is responsible for that.
-       order := temp(types.NewArray(types.Types[types.TUINT16], 2*int64(ncas)))
+       order := typecheck.Temp(types.NewArray(types.Types[types.TUINT16], 2*int64(ncas)))
 
        var pc0, pcs ir.Node
        if base.Flag.Race {
-               pcs = temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
-               pc0 = typecheck(nodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(0))), ctxExpr)
+               pcs = typecheck.Temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
+               pc0 = typecheck.Expr(typecheck.NodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(0))))
        } else {
-               pc0 = nodnil()
+               pc0 = typecheck.NodNil()
        }
 
        // register cases
                casorder[i] = cas
 
                setField := func(f string, val ir.Node) {
-                       r := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, ir.NewIndexExpr(base.Pos, selv, ir.NewInt(int64(i))), lookup(f)), val)
-                       init = append(init, typecheck(r, ctxStmt))
+                       r := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, ir.NewIndexExpr(base.Pos, selv, ir.NewInt(int64(i))), typecheck.Lookup(f)), val)
+                       init = append(init, typecheck.Stmt(r))
                }
 
-               c = convnop(c, types.Types[types.TUNSAFEPTR])
+               c = typecheck.ConvNop(c, types.Types[types.TUNSAFEPTR])
                setField("c", c)
                if !ir.IsBlank(elem) {
-                       elem = convnop(elem, types.Types[types.TUNSAFEPTR])
+                       elem = typecheck.ConvNop(elem, types.Types[types.TUNSAFEPTR])
                        setField("elem", elem)
                }
 
                // TODO(mdempsky): There should be a cleaner way to
                // handle this.
                if base.Flag.Race {
-                       r := mkcall("selectsetpc", nil, nil, nodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(int64(i)))))
+                       r := mkcall("selectsetpc", nil, nil, typecheck.NodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(int64(i)))))
                        init = append(init, r)
                }
        }
 
        // run the select
        base.Pos = sellineno
-       chosen := temp(types.Types[types.TINT])
-       recvOK := temp(types.Types[types.TBOOL])
+       chosen := typecheck.Temp(types.Types[types.TINT])
+       recvOK := typecheck.Temp(types.Types[types.TBOOL])
        r := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
        r.Lhs = []ir.Node{chosen, recvOK}
-       fn := syslook("selectgo")
+       fn := typecheck.LookupRuntime("selectgo")
        r.Rhs = []ir.Node{mkcall1(fn, fn.Type().Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, ir.NewInt(int64(nsends)), ir.NewInt(int64(nrecvs)), ir.NewBool(dflt == nil))}
-       init = append(init, typecheck(r, ctxStmt))
+       init = append(init, typecheck.Stmt(r))
 
        // selv and order are no longer alive after selectgo.
        init = append(init, ir.NewUnaryExpr(base.Pos, ir.OVARKILL, selv))
 
        // dispatch cases
        dispatch := func(cond ir.Node, cas *ir.CaseStmt) {
-               cond = typecheck(cond, ctxExpr)
-               cond = defaultlit(cond, nil)
+               cond = typecheck.Expr(cond)
+               cond = typecheck.DefaultLit(cond, nil)
 
                r := ir.NewIfStmt(base.Pos, cond, nil, nil)
 
                        n := n.(*ir.AssignListStmt)
                        if !ir.IsBlank(n.Lhs[1]) {
                                x := ir.NewAssignStmt(base.Pos, n.Lhs[1], recvOK)
-                               r.Body.Append(typecheck(x, ctxStmt))
+                               r.Body.Append(typecheck.Stmt(x))
                        }
                }
 
 
 // bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
 func bytePtrToIndex(n ir.Node, i int64) ir.Node {
-       s := nodAddr(ir.NewIndexExpr(base.Pos, n, ir.NewInt(i)))
+       s := typecheck.NodAddr(ir.NewIndexExpr(base.Pos, n, ir.NewInt(i)))
        t := types.NewPtr(types.Types[types.TUINT8])
-       return convnop(s, t)
+       return typecheck.ConvNop(s, t)
 }
 
 var scase *types.Type
 // Keep in sync with src/runtime/select.go.
 func scasetype() *types.Type {
        if scase == nil {
-               scase = tostruct([]*ir.Field{
-                       ir.NewField(base.Pos, lookup("c"), nil, types.Types[types.TUNSAFEPTR]),
-                       ir.NewField(base.Pos, lookup("elem"), nil, types.Types[types.TUNSAFEPTR]),
+               scase = typecheck.NewStructType([]*ir.Field{
+                       ir.NewField(base.Pos, typecheck.Lookup("c"), nil, types.Types[types.TUNSAFEPTR]),
+                       ir.NewField(base.Pos, typecheck.Lookup("elem"), nil, types.Types[types.TUNSAFEPTR]),
                })
                scase.SetNoalg(true)
        }
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "fmt"
                if loff != 0 || !types.Identical(typ, l.Type()) {
                        dst = ir.NewNameOffsetExpr(base.Pos, l, loff, typ)
                }
-               s.append(ir.NewAssignStmt(base.Pos, dst, conv(r, typ)))
+               s.append(ir.NewAssignStmt(base.Pos, dst, typecheck.Conv(r, typ)))
                return true
 
        case ir.ONIL:
 // Use readonlystaticname for read-only node.
 func staticname(t *types.Type) *ir.Name {
        // Don't use lookupN; it interns the resulting string, but these are all unique.
-       n := NewName(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
+       n := typecheck.NewName(typecheck.Lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
        statuniqgen++
-       declare(n, ir.PEXTERN)
+       typecheck.Declare(n, ir.PEXTERN)
        n.SetType(t)
        n.Sym().Linksym().Set(obj.AttrLocal, true)
        return n
                splitnode = func(r ir.Node) (ir.Node, ir.Node) {
                        if r.Op() == ir.OKEY {
                                kv := r.(*ir.KeyExpr)
-                               k = indexconst(kv.Key)
+                               k = typecheck.IndexConst(kv.Key)
                                if k < 0 {
                                        base.Fatalf("fixedlit: invalid index %v", kv.Key)
                                }
                // build list of assignments: var[index] = expr
                ir.SetPos(a)
                as := ir.NewAssignStmt(base.Pos, a, value)
-               as = typecheck(as, ctxStmt).(*ir.AssignStmt)
+               as = typecheck.Stmt(as).(*ir.AssignStmt)
                switch kind {
                case initKindStatic:
                        genAsStatic(as)
                fixedlit(ctxt, initKindDynamic, n, vstat, init)
 
                // copy static to slice
-               var_ = typecheck(var_, ctxExpr|ctxAssign)
+               var_ = typecheck.AssignExpr(var_)
                name, offset, ok := stataddr(var_)
                if !ok || name.Class_ != ir.PEXTERN {
                        base.Fatalf("slicelit: %v", var_)
        }
 
        // make new auto *array (3 declare)
-       vauto := temp(types.NewPtr(t))
+       vauto := typecheck.Temp(types.NewPtr(t))
 
        // set auto to point at new temp or heap (3 assign)
        var a ir.Node
 
                if vstat == nil {
                        a = ir.NewAssignStmt(base.Pos, x, nil)
-                       a = typecheck(a, ctxStmt)
+                       a = typecheck.Stmt(a)
                        init.Append(a) // zero new temp
                } else {
                        // Declare that we're about to initialize all of x.
                        init.Append(ir.NewUnaryExpr(base.Pos, ir.OVARDEF, x))
                }
 
-               a = nodAddr(x)
+               a = typecheck.NodAddr(x)
        } else if n.Esc() == ir.EscNone {
-               a = temp(t)
+               a = typecheck.Temp(t)
                if vstat == nil {
-                       a = ir.NewAssignStmt(base.Pos, temp(t), nil)
-                       a = typecheck(a, ctxStmt)
+                       a = ir.NewAssignStmt(base.Pos, typecheck.Temp(t), nil)
+                       a = typecheck.Stmt(a)
                        init.Append(a) // zero new temp
                        a = a.(*ir.AssignStmt).X
                } else {
                        init.Append(ir.NewUnaryExpr(base.Pos, ir.OVARDEF, a))
                }
 
-               a = nodAddr(a)
+               a = typecheck.NodAddr(a)
        } else {
                a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t))
        }
        for _, value := range n.List {
                if value.Op() == ir.OKEY {
                        kv := value.(*ir.KeyExpr)
-                       index = indexconst(kv.Key)
+                       index = typecheck.IndexConst(kv.Key)
                        if index < 0 {
                                base.Fatalf("slicelit: invalid index %v", kv.Key)
                        }
 
                // build list of vauto[c] = expr
                ir.SetPos(value)
-               as := typecheck(ir.NewAssignStmt(base.Pos, a, value), ctxStmt)
+               as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, a, value))
                as = orderStmtInPlace(as, map[string][]*ir.Name{})
                as = walkstmt(as)
                init.Append(as)
        // make slice out of heap (6)
        a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto))
 
-       a = typecheck(a, ctxStmt)
+       a = typecheck.Stmt(a)
        a = orderStmtInPlace(a, map[string][]*ir.Name{})
        a = walkstmt(a)
        init.Append(a)
                // for i = 0; i < len(vstatk); i++ {
                //      map[vstatk[i]] = vstate[i]
                // }
-               i := temp(types.Types[types.TINT])
+               i := typecheck.Temp(types.Types[types.TINT])
                rhs := ir.NewIndexExpr(base.Pos, vstate, i)
                rhs.SetBounded(true)
 
        // Build list of var[c] = expr.
        // Use temporaries so that mapassign1 can have addressable key, elem.
        // TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
-       tmpkey := temp(m.Type().Key())
-       tmpelem := temp(m.Type().Elem())
+       tmpkey := typecheck.Temp(m.Type().Key())
+       tmpelem := typecheck.Temp(m.Type().Elem())
 
        for _, r := range entries {
                r := r.(*ir.KeyExpr)
                if n.Alloc != nil {
                        // n.Right is stack temporary used as backing store.
                        appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n.Alloc, nil)) // zero backing store, just in case (#18410)
-                       r = nodAddr(n.Alloc)
+                       r = typecheck.NodAddr(n.Alloc)
                } else {
                        r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
                        r.SetEsc(n.Esc())
                appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
 
                var_ = ir.NewStarExpr(base.Pos, var_)
-               var_ = typecheck(var_, ctxExpr|ctxAssign)
+               var_ = typecheck.AssignExpr(var_)
                anylit(n.X, var_, init)
 
        case ir.OSTRUCTLIT, ir.OARRAYLIT:
                for _, a := range n.List {
                        if a.Op() == ir.OKEY {
                                kv := a.(*ir.KeyExpr)
-                               k = indexconst(kv.Key)
+                               k = typecheck.IndexConst(kv.Key)
                                if k < 0 {
                                        base.Fatalf("initplan arraylit: invalid index %v", kv.Key)
                                }
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/ssa"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/obj/x86"
        ssaCaches = make([]ssa.Cache, base.Flag.LowerC)
 
        // Set up some runtime functions we'll need to call.
-       ir.Syms.AssertE2I = sysfunc("assertE2I")
-       ir.Syms.AssertE2I2 = sysfunc("assertE2I2")
-       ir.Syms.AssertI2I = sysfunc("assertI2I")
-       ir.Syms.AssertI2I2 = sysfunc("assertI2I2")
-       ir.Syms.Deferproc = sysfunc("deferproc")
-       ir.Syms.DeferprocStack = sysfunc("deferprocStack")
-       ir.Syms.Deferreturn = sysfunc("deferreturn")
-       ir.Syms.Duffcopy = sysfunc("duffcopy")
-       ir.Syms.Duffzero = sysfunc("duffzero")
-       ir.Syms.GCWriteBarrier = sysfunc("gcWriteBarrier")
-       ir.Syms.Goschedguarded = sysfunc("goschedguarded")
-       ir.Syms.Growslice = sysfunc("growslice")
-       ir.Syms.Msanread = sysfunc("msanread")
-       ir.Syms.Msanwrite = sysfunc("msanwrite")
-       ir.Syms.Msanmove = sysfunc("msanmove")
-       ir.Syms.Newobject = sysfunc("newobject")
-       ir.Syms.Newproc = sysfunc("newproc")
-       ir.Syms.Panicdivide = sysfunc("panicdivide")
-       ir.Syms.PanicdottypeE = sysfunc("panicdottypeE")
-       ir.Syms.PanicdottypeI = sysfunc("panicdottypeI")
-       ir.Syms.Panicnildottype = sysfunc("panicnildottype")
-       ir.Syms.Panicoverflow = sysfunc("panicoverflow")
-       ir.Syms.Panicshift = sysfunc("panicshift")
-       ir.Syms.Raceread = sysfunc("raceread")
-       ir.Syms.Racereadrange = sysfunc("racereadrange")
-       ir.Syms.Racewrite = sysfunc("racewrite")
-       ir.Syms.Racewriterange = sysfunc("racewriterange")
-       ir.Syms.X86HasPOPCNT = sysvar("x86HasPOPCNT")       // bool
-       ir.Syms.X86HasSSE41 = sysvar("x86HasSSE41")         // bool
-       ir.Syms.X86HasFMA = sysvar("x86HasFMA")             // bool
-       ir.Syms.ARMHasVFPv4 = sysvar("armHasVFPv4")         // bool
-       ir.Syms.ARM64HasATOMICS = sysvar("arm64HasATOMICS") // bool
-       ir.Syms.Typedmemclr = sysfunc("typedmemclr")
-       ir.Syms.Typedmemmove = sysfunc("typedmemmove")
-       ir.Syms.Udiv = sysvar("udiv")                 // asm func with special ABI
-       ir.Syms.WriteBarrier = sysvar("writeBarrier") // struct { bool; ... }
-       ir.Syms.Zerobase = sysvar("zerobase")
+       ir.Syms.AssertE2I = typecheck.LookupRuntimeFunc("assertE2I")
+       ir.Syms.AssertE2I2 = typecheck.LookupRuntimeFunc("assertE2I2")
+       ir.Syms.AssertI2I = typecheck.LookupRuntimeFunc("assertI2I")
+       ir.Syms.AssertI2I2 = typecheck.LookupRuntimeFunc("assertI2I2")
+       ir.Syms.Deferproc = typecheck.LookupRuntimeFunc("deferproc")
+       ir.Syms.DeferprocStack = typecheck.LookupRuntimeFunc("deferprocStack")
+       ir.Syms.Deferreturn = typecheck.LookupRuntimeFunc("deferreturn")
+       ir.Syms.Duffcopy = typecheck.LookupRuntimeFunc("duffcopy")
+       ir.Syms.Duffzero = typecheck.LookupRuntimeFunc("duffzero")
+       ir.Syms.GCWriteBarrier = typecheck.LookupRuntimeFunc("gcWriteBarrier")
+       ir.Syms.Goschedguarded = typecheck.LookupRuntimeFunc("goschedguarded")
+       ir.Syms.Growslice = typecheck.LookupRuntimeFunc("growslice")
+       ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread")
+       ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite")
+       ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove")
+       ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject")
+       ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc")
+       ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide")
+       ir.Syms.PanicdottypeE = typecheck.LookupRuntimeFunc("panicdottypeE")
+       ir.Syms.PanicdottypeI = typecheck.LookupRuntimeFunc("panicdottypeI")
+       ir.Syms.Panicnildottype = typecheck.LookupRuntimeFunc("panicnildottype")
+       ir.Syms.Panicoverflow = typecheck.LookupRuntimeFunc("panicoverflow")
+       ir.Syms.Panicshift = typecheck.LookupRuntimeFunc("panicshift")
+       ir.Syms.Raceread = typecheck.LookupRuntimeFunc("raceread")
+       ir.Syms.Racereadrange = typecheck.LookupRuntimeFunc("racereadrange")
+       ir.Syms.Racewrite = typecheck.LookupRuntimeFunc("racewrite")
+       ir.Syms.Racewriterange = typecheck.LookupRuntimeFunc("racewriterange")
+       ir.Syms.X86HasPOPCNT = typecheck.LookupRuntimeVar("x86HasPOPCNT")       // bool
+       ir.Syms.X86HasSSE41 = typecheck.LookupRuntimeVar("x86HasSSE41")         // bool
+       ir.Syms.X86HasFMA = typecheck.LookupRuntimeVar("x86HasFMA")             // bool
+       ir.Syms.ARMHasVFPv4 = typecheck.LookupRuntimeVar("armHasVFPv4")         // bool
+       ir.Syms.ARM64HasATOMICS = typecheck.LookupRuntimeVar("arm64HasATOMICS") // bool
+       ir.Syms.Typedmemclr = typecheck.LookupRuntimeFunc("typedmemclr")
+       ir.Syms.Typedmemmove = typecheck.LookupRuntimeFunc("typedmemmove")
+       ir.Syms.Udiv = typecheck.LookupRuntimeVar("udiv")                 // asm func with special ABI
+       ir.Syms.WriteBarrier = typecheck.LookupRuntimeVar("writeBarrier") // struct { bool; ... }
+       ir.Syms.Zerobase = typecheck.LookupRuntimeVar("zerobase")
 
        // asm funcs with special ABI
        if thearch.LinkArch.Name == "amd64" {
                GCWriteBarrierReg = map[int16]*obj.LSym{
-                       x86.REG_AX: sysfunc("gcWriteBarrier"),
-                       x86.REG_CX: sysfunc("gcWriteBarrierCX"),
-                       x86.REG_DX: sysfunc("gcWriteBarrierDX"),
-                       x86.REG_BX: sysfunc("gcWriteBarrierBX"),
-                       x86.REG_BP: sysfunc("gcWriteBarrierBP"),
-                       x86.REG_SI: sysfunc("gcWriteBarrierSI"),
-                       x86.REG_R8: sysfunc("gcWriteBarrierR8"),
-                       x86.REG_R9: sysfunc("gcWriteBarrierR9"),
+                       x86.REG_AX: typecheck.LookupRuntimeFunc("gcWriteBarrier"),
+                       x86.REG_CX: typecheck.LookupRuntimeFunc("gcWriteBarrierCX"),
+                       x86.REG_DX: typecheck.LookupRuntimeFunc("gcWriteBarrierDX"),
+                       x86.REG_BX: typecheck.LookupRuntimeFunc("gcWriteBarrierBX"),
+                       x86.REG_BP: typecheck.LookupRuntimeFunc("gcWriteBarrierBP"),
+                       x86.REG_SI: typecheck.LookupRuntimeFunc("gcWriteBarrierSI"),
+                       x86.REG_R8: typecheck.LookupRuntimeFunc("gcWriteBarrierR8"),
+                       x86.REG_R9: typecheck.LookupRuntimeFunc("gcWriteBarrierR9"),
                }
        }
 
        if thearch.LinkArch.Family == sys.Wasm {
-               BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("goPanicIndex")
-               BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("goPanicIndexU")
-               BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("goPanicSliceAlen")
-               BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("goPanicSliceAlenU")
-               BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("goPanicSliceAcap")
-               BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("goPanicSliceAcapU")
-               BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("goPanicSliceB")
-               BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("goPanicSliceBU")
-               BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("goPanicSlice3Alen")
-               BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("goPanicSlice3AlenU")
-               BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("goPanicSlice3Acap")
-               BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("goPanicSlice3AcapU")
-               BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("goPanicSlice3B")
-               BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("goPanicSlice3BU")
-               BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("goPanicSlice3C")
-               BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("goPanicSlice3CU")
+               BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("goPanicIndex")
+               BoundsCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeFunc("goPanicIndexU")
+               BoundsCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeFunc("goPanicSliceAlen")
+               BoundsCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeFunc("goPanicSliceAlenU")
+               BoundsCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeFunc("goPanicSliceAcap")
+               BoundsCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeFunc("goPanicSliceAcapU")
+               BoundsCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeFunc("goPanicSliceB")
+               BoundsCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeFunc("goPanicSliceBU")
+               BoundsCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeFunc("goPanicSlice3Alen")
+               BoundsCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeFunc("goPanicSlice3AlenU")
+               BoundsCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeFunc("goPanicSlice3Acap")
+               BoundsCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeFunc("goPanicSlice3AcapU")
+               BoundsCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeFunc("goPanicSlice3B")
+               BoundsCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeFunc("goPanicSlice3BU")
+               BoundsCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeFunc("goPanicSlice3C")
+               BoundsCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeFunc("goPanicSlice3CU")
        } else {
-               BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("panicIndex")
-               BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("panicIndexU")
-               BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("panicSliceAlen")
-               BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("panicSliceAlenU")
-               BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("panicSliceAcap")
-               BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("panicSliceAcapU")
-               BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("panicSliceB")
-               BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("panicSliceBU")
-               BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("panicSlice3Alen")
-               BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("panicSlice3AlenU")
-               BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("panicSlice3Acap")
-               BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("panicSlice3AcapU")
-               BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("panicSlice3B")
-               BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("panicSlice3BU")
-               BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("panicSlice3C")
-               BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("panicSlice3CU")
+               BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("panicIndex")
+               BoundsCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeFunc("panicIndexU")
+               BoundsCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeFunc("panicSliceAlen")
+               BoundsCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeFunc("panicSliceAlenU")
+               BoundsCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeFunc("panicSliceAcap")
+               BoundsCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeFunc("panicSliceAcapU")
+               BoundsCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeFunc("panicSliceB")
+               BoundsCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeFunc("panicSliceBU")
+               BoundsCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeFunc("panicSlice3Alen")
+               BoundsCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeFunc("panicSlice3AlenU")
+               BoundsCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeFunc("panicSlice3Acap")
+               BoundsCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeFunc("panicSlice3AcapU")
+               BoundsCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeFunc("panicSlice3B")
+               BoundsCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeFunc("panicSlice3BU")
+               BoundsCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeFunc("panicSlice3C")
+               BoundsCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeFunc("panicSlice3CU")
        }
        if thearch.LinkArch.PtrSize == 4 {
-               ExtendCheckFunc[ssa.BoundsIndex] = sysvar("panicExtendIndex")
-               ExtendCheckFunc[ssa.BoundsIndexU] = sysvar("panicExtendIndexU")
-               ExtendCheckFunc[ssa.BoundsSliceAlen] = sysvar("panicExtendSliceAlen")
-               ExtendCheckFunc[ssa.BoundsSliceAlenU] = sysvar("panicExtendSliceAlenU")
-               ExtendCheckFunc[ssa.BoundsSliceAcap] = sysvar("panicExtendSliceAcap")
-               ExtendCheckFunc[ssa.BoundsSliceAcapU] = sysvar("panicExtendSliceAcapU")
-               ExtendCheckFunc[ssa.BoundsSliceB] = sysvar("panicExtendSliceB")
-               ExtendCheckFunc[ssa.BoundsSliceBU] = sysvar("panicExtendSliceBU")
-               ExtendCheckFunc[ssa.BoundsSlice3Alen] = sysvar("panicExtendSlice3Alen")
-               ExtendCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("panicExtendSlice3AlenU")
-               ExtendCheckFunc[ssa.BoundsSlice3Acap] = sysvar("panicExtendSlice3Acap")
-               ExtendCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("panicExtendSlice3AcapU")
-               ExtendCheckFunc[ssa.BoundsSlice3B] = sysvar("panicExtendSlice3B")
-               ExtendCheckFunc[ssa.BoundsSlice3BU] = sysvar("panicExtendSlice3BU")
-               ExtendCheckFunc[ssa.BoundsSlice3C] = sysvar("panicExtendSlice3C")
-               ExtendCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicExtendSlice3CU")
+               ExtendCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeVar("panicExtendIndex")
+               ExtendCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeVar("panicExtendIndexU")
+               ExtendCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeVar("panicExtendSliceAlen")
+               ExtendCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeVar("panicExtendSliceAlenU")
+               ExtendCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeVar("panicExtendSliceAcap")
+               ExtendCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeVar("panicExtendSliceAcapU")
+               ExtendCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeVar("panicExtendSliceB")
+               ExtendCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeVar("panicExtendSliceBU")
+               ExtendCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeVar("panicExtendSlice3Alen")
+               ExtendCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeVar("panicExtendSlice3AlenU")
+               ExtendCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeVar("panicExtendSlice3Acap")
+               ExtendCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeVar("panicExtendSlice3AcapU")
+               ExtendCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeVar("panicExtendSlice3B")
+               ExtendCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeVar("panicExtendSlice3BU")
+               ExtendCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeVar("panicExtendSlice3C")
+               ExtendCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeVar("panicExtendSlice3CU")
        }
 
        // Wasm (all asm funcs with special ABIs)
-       ir.Syms.WasmMove = sysvar("wasmMove")
-       ir.Syms.WasmZero = sysvar("wasmZero")
-       ir.Syms.WasmDiv = sysvar("wasmDiv")
-       ir.Syms.WasmTruncS = sysvar("wasmTruncS")
-       ir.Syms.WasmTruncU = sysvar("wasmTruncU")
-       ir.Syms.SigPanic = sysfunc("sigpanic")
+       ir.Syms.WasmMove = typecheck.LookupRuntimeVar("wasmMove")
+       ir.Syms.WasmZero = typecheck.LookupRuntimeVar("wasmZero")
+       ir.Syms.WasmDiv = typecheck.LookupRuntimeVar("wasmDiv")
+       ir.Syms.WasmTruncS = typecheck.LookupRuntimeVar("wasmTruncS")
+       ir.Syms.WasmTruncU = typecheck.LookupRuntimeVar("wasmTruncU")
+       ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic")
 }
 
 // getParam returns the Field of ith param of node n (which is a
                // Create the deferBits variable and stack slot.  deferBits is a
                // bitmask showing which of the open-coded defers in this function
                // have been activated.
-               deferBitsTemp := tempAt(src.NoXPos, s.curfn, types.Types[types.TUINT8])
+               deferBitsTemp := typecheck.TempAt(src.NoXPos, s.curfn, types.Types[types.TUINT8])
                s.deferBitsTemp = deferBitsTemp
                // For this value, AuxInt is initialized to zero by default
                startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[types.TUINT8])
 func (s *state) Debug_checknil() bool                                { return s.f.Frontend().Debug_checknil() }
 
 func ssaMarker(name string) *ir.Name {
-       return NewName(&types.Sym{Name: name})
+       return typecheck.NewName(&types.Sym{Name: name})
 }
 
 var (
 func softfloatInit() {
        // Some of these operations get transformed by sfcall.
        softFloatOps = map[ssa.Op]sfRtCallDef{
-               ssa.OpAdd32F: sfRtCallDef{sysfunc("fadd32"), types.TFLOAT32},
-               ssa.OpAdd64F: sfRtCallDef{sysfunc("fadd64"), types.TFLOAT64},
-               ssa.OpSub32F: sfRtCallDef{sysfunc("fadd32"), types.TFLOAT32},
-               ssa.OpSub64F: sfRtCallDef{sysfunc("fadd64"), types.TFLOAT64},
-               ssa.OpMul32F: sfRtCallDef{sysfunc("fmul32"), types.TFLOAT32},
-               ssa.OpMul64F: sfRtCallDef{sysfunc("fmul64"), types.TFLOAT64},
-               ssa.OpDiv32F: sfRtCallDef{sysfunc("fdiv32"), types.TFLOAT32},
-               ssa.OpDiv64F: sfRtCallDef{sysfunc("fdiv64"), types.TFLOAT64},
-
-               ssa.OpEq64F:   sfRtCallDef{sysfunc("feq64"), types.TBOOL},
-               ssa.OpEq32F:   sfRtCallDef{sysfunc("feq32"), types.TBOOL},
-               ssa.OpNeq64F:  sfRtCallDef{sysfunc("feq64"), types.TBOOL},
-               ssa.OpNeq32F:  sfRtCallDef{sysfunc("feq32"), types.TBOOL},
-               ssa.OpLess64F: sfRtCallDef{sysfunc("fgt64"), types.TBOOL},
-               ssa.OpLess32F: sfRtCallDef{sysfunc("fgt32"), types.TBOOL},
-               ssa.OpLeq64F:  sfRtCallDef{sysfunc("fge64"), types.TBOOL},
-               ssa.OpLeq32F:  sfRtCallDef{sysfunc("fge32"), types.TBOOL},
-
-               ssa.OpCvt32to32F:  sfRtCallDef{sysfunc("fint32to32"), types.TFLOAT32},
-               ssa.OpCvt32Fto32:  sfRtCallDef{sysfunc("f32toint32"), types.TINT32},
-               ssa.OpCvt64to32F:  sfRtCallDef{sysfunc("fint64to32"), types.TFLOAT32},
-               ssa.OpCvt32Fto64:  sfRtCallDef{sysfunc("f32toint64"), types.TINT64},
-               ssa.OpCvt64Uto32F: sfRtCallDef{sysfunc("fuint64to32"), types.TFLOAT32},
-               ssa.OpCvt32Fto64U: sfRtCallDef{sysfunc("f32touint64"), types.TUINT64},
-               ssa.OpCvt32to64F:  sfRtCallDef{sysfunc("fint32to64"), types.TFLOAT64},
-               ssa.OpCvt64Fto32:  sfRtCallDef{sysfunc("f64toint32"), types.TINT32},
-               ssa.OpCvt64to64F:  sfRtCallDef{sysfunc("fint64to64"), types.TFLOAT64},
-               ssa.OpCvt64Fto64:  sfRtCallDef{sysfunc("f64toint64"), types.TINT64},
-               ssa.OpCvt64Uto64F: sfRtCallDef{sysfunc("fuint64to64"), types.TFLOAT64},
-               ssa.OpCvt64Fto64U: sfRtCallDef{sysfunc("f64touint64"), types.TUINT64},
-               ssa.OpCvt32Fto64F: sfRtCallDef{sysfunc("f32to64"), types.TFLOAT64},
-               ssa.OpCvt64Fto32F: sfRtCallDef{sysfunc("f64to32"), types.TFLOAT32},
+               ssa.OpAdd32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
+               ssa.OpAdd64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
+               ssa.OpSub32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
+               ssa.OpSub64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
+               ssa.OpMul32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fmul32"), types.TFLOAT32},
+               ssa.OpMul64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fmul64"), types.TFLOAT64},
+               ssa.OpDiv32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fdiv32"), types.TFLOAT32},
+               ssa.OpDiv64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fdiv64"), types.TFLOAT64},
+
+               ssa.OpEq64F:   sfRtCallDef{typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
+               ssa.OpEq32F:   sfRtCallDef{typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
+               ssa.OpNeq64F:  sfRtCallDef{typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
+               ssa.OpNeq32F:  sfRtCallDef{typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
+               ssa.OpLess64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fgt64"), types.TBOOL},
+               ssa.OpLess32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fgt32"), types.TBOOL},
+               ssa.OpLeq64F:  sfRtCallDef{typecheck.LookupRuntimeFunc("fge64"), types.TBOOL},
+               ssa.OpLeq32F:  sfRtCallDef{typecheck.LookupRuntimeFunc("fge32"), types.TBOOL},
+
+               ssa.OpCvt32to32F:  sfRtCallDef{typecheck.LookupRuntimeFunc("fint32to32"), types.TFLOAT32},
+               ssa.OpCvt32Fto32:  sfRtCallDef{typecheck.LookupRuntimeFunc("f32toint32"), types.TINT32},
+               ssa.OpCvt64to32F:  sfRtCallDef{typecheck.LookupRuntimeFunc("fint64to32"), types.TFLOAT32},
+               ssa.OpCvt32Fto64:  sfRtCallDef{typecheck.LookupRuntimeFunc("f32toint64"), types.TINT64},
+               ssa.OpCvt64Uto32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fuint64to32"), types.TFLOAT32},
+               ssa.OpCvt32Fto64U: sfRtCallDef{typecheck.LookupRuntimeFunc("f32touint64"), types.TUINT64},
+               ssa.OpCvt32to64F:  sfRtCallDef{typecheck.LookupRuntimeFunc("fint32to64"), types.TFLOAT64},
+               ssa.OpCvt64Fto32:  sfRtCallDef{typecheck.LookupRuntimeFunc("f64toint32"), types.TINT32},
+               ssa.OpCvt64to64F:  sfRtCallDef{typecheck.LookupRuntimeFunc("fint64to64"), types.TFLOAT64},
+               ssa.OpCvt64Fto64:  sfRtCallDef{typecheck.LookupRuntimeFunc("f64toint64"), types.TINT64},
+               ssa.OpCvt64Uto64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fuint64to64"), types.TFLOAT64},
+               ssa.OpCvt64Fto64U: sfRtCallDef{typecheck.LookupRuntimeFunc("f64touint64"), types.TUINT64},
+               ssa.OpCvt32Fto64F: sfRtCallDef{typecheck.LookupRuntimeFunc("f32to64"), types.TFLOAT64},
+               ssa.OpCvt64Fto32F: sfRtCallDef{typecheck.LookupRuntimeFunc("f64to32"), types.TFLOAT32},
        }
 }
 
        } else {
                pos = n.Pos()
        }
-       argTemp := tempAt(pos.WithNotStmt(), s.curfn, t)
+       argTemp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
        argTemp.SetOpenDeferSlot(true)
        var addrArgTemp *ssa.Value
        // Use OpVarLive to make sure stack slots for the args, etc. are not
                testLateExpansion = ssa.LateCallExpansionEnabledWithin(s.f)
                // Make a defer struct d on the stack.
                t := deferstruct(stksize)
-               d := tempAt(n.Pos(), s.curfn, t)
+               d := typecheck.TempAt(n.Pos(), s.curfn, t)
 
                s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, d, s.mem())
                addr := s.addr(d)
        if commaok && !canSSAType(n.Type()) {
                // unSSAable type, use temporary.
                // TODO: get rid of some of these temporaries.
-               tmp = tempAt(n.Pos(), s.curfn, n.Type())
+               tmp = typecheck.TempAt(n.Pos(), s.curfn, n.Type())
                s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp.(*ir.Name), s.mem())
                addr = s.addr(tmp)
        }
 }
 
 func (e *ssafn) Auto(pos src.XPos, t *types.Type) *ir.Name {
-       return tempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
+       return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
 }
 
 func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
        "fmt"
-       "sort"
-       "strconv"
        "strings"
        "sync"
        "unicode"
        largeStackFrames   []largeStack
 )
 
-func lookup(name string) *types.Sym {
-       return types.LocalPkg.Lookup(name)
-}
-
-// lookupN looks up the symbol starting with prefix and ending with
-// the decimal n. If prefix is too long, lookupN panics.
-func lookupN(prefix string, n int) *types.Sym {
-       var buf [20]byte // plenty long enough for all current users
-       copy(buf[:], prefix)
-       b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
-       return types.LocalPkg.LookupBytes(b)
-}
-
-// autolabel generates a new Name node for use with
-// an automatically generated label.
-// prefix is a short mnemonic (e.g. ".s" for switch)
-// to help with debugging.
-// It should begin with "." to avoid conflicts with
-// user labels.
-func autolabel(prefix string) *types.Sym {
-       if prefix[0] != '.' {
-               base.Fatalf("autolabel prefix must start with '.', have %q", prefix)
-       }
-       fn := ir.CurFunc
-       if ir.CurFunc == nil {
-               base.Fatalf("autolabel outside function")
-       }
-       n := fn.Label
-       fn.Label++
-       return lookupN(prefix, int(n))
-}
-
 // dotImports tracks all PkgNames that have been dot-imported.
 var dotImports []*ir.PkgName
 
-// dotImportRefs maps idents introduced by importDot back to the
-// ir.PkgName they were dot-imported through.
-var dotImportRefs map[*ir.Ident]*ir.PkgName
-
 // find all the exported symbols in package referenced by PkgName,
 // and make them available in the current package
 func importDot(pack *ir.PkgName) {
-       if dotImportRefs == nil {
-               dotImportRefs = make(map[*ir.Ident]*ir.PkgName)
+       if typecheck.DotImportRefs == nil {
+               typecheck.DotImportRefs = make(map[*ir.Ident]*ir.PkgName)
        }
 
        opkg := pack.Pkg
        for _, s := range opkg.Syms {
                if s.Def == nil {
-                       if _, ok := declImporter[s]; !ok {
+                       if _, ok := typecheck.DeclImporter[s]; !ok {
                                continue
                        }
                }
                if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
                        continue
                }
-               s1 := lookup(s.Name)
+               s1 := typecheck.Lookup(s.Name)
                if s1.Def != nil {
                        pkgerror := fmt.Sprintf("during import %q", opkg.Path)
-                       redeclare(base.Pos, s1, pkgerror)
+                       typecheck.Redeclared(base.Pos, s1, pkgerror)
                        continue
                }
 
                id := ir.NewIdent(src.NoXPos, s)
-               dotImportRefs[id] = pack
+               typecheck.DotImportRefs[id] = pack
                s1.Def = id
                s1.Block = 1
        }
 
        // No longer needed; release memory.
        dotImports = nil
-       dotImportRefs = nil
-}
-
-// nodAddr returns a node representing &n at base.Pos.
-func nodAddr(n ir.Node) *ir.AddrExpr {
-       return nodAddrAt(base.Pos, n)
-}
-
-// nodAddrPos returns a node representing &n at position pos.
-func nodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
-       return ir.NewAddrExpr(pos, n)
-}
-
-// newname returns a new ONAME Node associated with symbol s.
-func NewName(s *types.Sym) *ir.Name {
-       n := ir.NewNameAt(base.Pos, s)
-       n.Curfn = ir.CurFunc
-       return n
-}
-
-func nodnil() ir.Node {
-       n := ir.NewNilExpr(base.Pos)
-       n.SetType(types.Types[types.TNIL])
-       return n
-}
-
-func isptrto(t *types.Type, et types.Kind) bool {
-       if t == nil {
-               return false
-       }
-       if !t.IsPtr() {
-               return false
-       }
-       t = t.Elem()
-       if t == nil {
-               return false
-       }
-       if t.Kind() != et {
-               return false
-       }
-       return true
-}
-
-// Is type src assignment compatible to type dst?
-// If so, return op code to use in conversion.
-// If not, return OXXX. In this case, the string return parameter may
-// hold a reason why. In all other cases, it'll be the empty string.
-func assignop(src, dst *types.Type) (ir.Op, string) {
-       if src == dst {
-               return ir.OCONVNOP, ""
-       }
-       if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
-               return ir.OXXX, ""
-       }
-
-       // 1. src type is identical to dst.
-       if types.Identical(src, dst) {
-               return ir.OCONVNOP, ""
-       }
-
-       // 2. src and dst have identical underlying types
-       // and either src or dst is not a named type or
-       // both are empty interface types.
-       // For assignable but different non-empty interface types,
-       // we want to recompute the itab. Recomputing the itab ensures
-       // that itabs are unique (thus an interface with a compile-time
-       // type I has an itab with interface type I).
-       if types.Identical(src.Underlying(), dst.Underlying()) {
-               if src.IsEmptyInterface() {
-                       // Conversion between two empty interfaces
-                       // requires no code.
-                       return ir.OCONVNOP, ""
-               }
-               if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() {
-                       // Conversion between two types, at least one unnamed,
-                       // needs no conversion. The exception is nonempty interfaces
-                       // which need to have their itab updated.
-                       return ir.OCONVNOP, ""
-               }
-       }
-
-       // 3. dst is an interface type and src implements dst.
-       if dst.IsInterface() && src.Kind() != types.TNIL {
-               var missing, have *types.Field
-               var ptr int
-               if implements(src, dst, &missing, &have, &ptr) {
-                       // Call itabname so that (src, dst)
-                       // gets added to itabs early, which allows
-                       // us to de-virtualize calls through this
-                       // type/interface pair later. See peekitabs in reflect.go
-                       if types.IsDirectIface(src) && !dst.IsEmptyInterface() {
-                               NeedITab(src, dst)
-                       }
-
-                       return ir.OCONVIFACE, ""
-               }
-
-               // we'll have complained about this method anyway, suppress spurious messages.
-               if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
-                       return ir.OCONVIFACE, ""
-               }
-
-               var why string
-               if isptrto(src, types.TINTER) {
-                       why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
-               } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
-                       why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
-               } else if have != nil && have.Sym == missing.Sym {
-                       why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
-                               "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
-               } else if ptr != 0 {
-                       why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
-               } else if have != nil {
-                       why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
-                               "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
-               } else {
-                       why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
-               }
-
-               return ir.OXXX, why
-       }
-
-       if isptrto(dst, types.TINTER) {
-               why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
-               return ir.OXXX, why
-       }
-
-       if src.IsInterface() && dst.Kind() != types.TBLANK {
-               var missing, have *types.Field
-               var ptr int
-               var why string
-               if implements(dst, src, &missing, &have, &ptr) {
-                       why = ": need type assertion"
-               }
-               return ir.OXXX, why
-       }
-
-       // 4. src is a bidirectional channel value, dst is a channel type,
-       // src and dst have identical element types, and
-       // either src or dst is not a named type.
-       if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
-               if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) {
-                       return ir.OCONVNOP, ""
-               }
-       }
-
-       // 5. src is the predeclared identifier nil and dst is a nillable type.
-       if src.Kind() == types.TNIL {
-               switch dst.Kind() {
-               case types.TPTR,
-                       types.TFUNC,
-                       types.TMAP,
-                       types.TCHAN,
-                       types.TINTER,
-                       types.TSLICE:
-                       return ir.OCONVNOP, ""
-               }
-       }
-
-       // 6. rule about untyped constants - already converted by defaultlit.
-
-       // 7. Any typed value can be assigned to the blank identifier.
-       if dst.Kind() == types.TBLANK {
-               return ir.OCONVNOP, ""
-       }
-
-       return ir.OXXX, ""
-}
-
-// Can we convert a value of type src to a value of type dst?
-// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return OXXX. In this case, the string return parameter may
-// hold a reason why. In all other cases, it'll be the empty string.
-// srcConstant indicates whether the value of type src is a constant.
-func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
-       if src == dst {
-               return ir.OCONVNOP, ""
-       }
-       if src == nil || dst == nil {
-               return ir.OXXX, ""
-       }
-
-       // Conversions from regular to go:notinheap are not allowed
-       // (unless it's unsafe.Pointer). These are runtime-specific
-       // rules.
-       // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
-       if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
-               why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
-               return ir.OXXX, why
-       }
-       // (b) Disallow string to []T where T is go:notinheap.
-       if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) {
-               why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
-               return ir.OXXX, why
-       }
-
-       // 1. src can be assigned to dst.
-       op, why := assignop(src, dst)
-       if op != ir.OXXX {
-               return op, why
-       }
-
-       // The rules for interfaces are no different in conversions
-       // than assignments. If interfaces are involved, stop now
-       // with the good message from assignop.
-       // Otherwise clear the error.
-       if src.IsInterface() || dst.IsInterface() {
-               return ir.OXXX, why
-       }
-
-       // 2. Ignoring struct tags, src and dst have identical underlying types.
-       if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) {
-               return ir.OCONVNOP, ""
-       }
-
-       // 3. src and dst are unnamed pointer types and, ignoring struct tags,
-       // their base types have identical underlying types.
-       if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil {
-               if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) {
-                       return ir.OCONVNOP, ""
-               }
-       }
-
-       // 4. src and dst are both integer or floating point types.
-       if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
-               if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
-                       return ir.OCONVNOP, ""
-               }
-               return ir.OCONV, ""
-       }
-
-       // 5. src and dst are both complex types.
-       if src.IsComplex() && dst.IsComplex() {
-               if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
-                       return ir.OCONVNOP, ""
-               }
-               return ir.OCONV, ""
-       }
-
-       // Special case for constant conversions: any numeric
-       // conversion is potentially okay. We'll validate further
-       // within evconst. See #38117.
-       if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
-               return ir.OCONV, ""
-       }
-
-       // 6. src is an integer or has type []byte or []rune
-       // and dst is a string type.
-       if src.IsInteger() && dst.IsString() {
-               return ir.ORUNESTR, ""
-       }
-
-       if src.IsSlice() && dst.IsString() {
-               if src.Elem().Kind() == types.ByteType.Kind() {
-                       return ir.OBYTES2STR, ""
-               }
-               if src.Elem().Kind() == types.RuneType.Kind() {
-                       return ir.ORUNES2STR, ""
-               }
-       }
-
-       // 7. src is a string and dst is []byte or []rune.
-       // String to slice.
-       if src.IsString() && dst.IsSlice() {
-               if dst.Elem().Kind() == types.ByteType.Kind() {
-                       return ir.OSTR2BYTES, ""
-               }
-               if dst.Elem().Kind() == types.RuneType.Kind() {
-                       return ir.OSTR2RUNES, ""
-               }
-       }
-
-       // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
-       if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
-               return ir.OCONVNOP, ""
-       }
-
-       // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
-       if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
-               return ir.OCONVNOP, ""
-       }
-
-       // src is map and dst is a pointer to corresponding hmap.
-       // This rule is needed for the implementation detail that
-       // go gc maps are implemented as a pointer to a hmap struct.
-       if src.Kind() == types.TMAP && dst.IsPtr() &&
-               src.MapType().Hmap == dst.Elem() {
-               return ir.OCONVNOP, ""
-       }
-
-       return ir.OXXX, ""
-}
-
-func assignconv(n ir.Node, t *types.Type, context string) ir.Node {
-       return assignconvfn(n, t, func() string { return context })
-}
-
-// Convert node n for assignment to type t.
-func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
-       if n == nil || n.Type() == nil || n.Type().Broke() {
-               return n
-       }
-
-       if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL {
-               base.Errorf("use of untyped nil")
-       }
-
-       n = convlit1(n, t, false, context)
-       if n.Type() == nil {
-               return n
-       }
-       if t.Kind() == types.TBLANK {
-               return n
-       }
-
-       // Convert ideal bool from comparison to plain bool
-       // if the next step is non-bool (like interface{}).
-       if n.Type() == types.UntypedBool && !t.IsBoolean() {
-               if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL {
-                       r := ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
-                       r.SetType(types.Types[types.TBOOL])
-                       r.SetTypecheck(1)
-                       r.SetImplicit(true)
-                       n = r
-               }
-       }
-
-       if types.Identical(n.Type(), t) {
-               return n
-       }
-
-       op, why := assignop(n.Type(), t)
-       if op == ir.OXXX {
-               base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
-               op = ir.OCONV
-       }
-
-       r := ir.NewConvExpr(base.Pos, op, t, n)
-       r.SetTypecheck(1)
-       r.SetImplicit(true)
-       return r
+       typecheck.DotImportRefs = nil
 }
 
 // backingArrayPtrLen extracts the pointer and length from a slice or string.
        return ptr, length
 }
 
-func syslook(name string) *ir.Name {
-       s := ir.Pkgs.Runtime.Lookup(name)
-       if s == nil || s.Def == nil {
-               base.Fatalf("syslook: can't find runtime.%s", name)
-       }
-       return ir.AsNode(s.Def).(*ir.Name)
-}
-
 // updateHasCall checks whether expression n contains any function
 // calls and sets the n.HasCall flag if so.
 func updateHasCall(n ir.Node) {
                }
                a := ir.Copy(n).(*ir.UnaryExpr)
                a.X = l
-               return walkexpr(typecheck(a, ctxExpr), init)
+               return walkexpr(typecheck.Expr(a), init)
 
        case ir.ODOT, ir.ODOTPTR:
                n := n.(*ir.SelectorExpr)
                }
                a := ir.Copy(n).(*ir.SelectorExpr)
                a.X = l
-               return walkexpr(typecheck(a, ctxExpr), init)
+               return walkexpr(typecheck.Expr(a), init)
 
        case ir.ODEREF:
                n := n.(*ir.StarExpr)
                }
                a := ir.Copy(n).(*ir.StarExpr)
                a.X = l
-               return walkexpr(typecheck(a, ctxExpr), init)
+               return walkexpr(typecheck.Expr(a), init)
 
        case ir.OINDEX, ir.OINDEXMAP:
                n := n.(*ir.IndexExpr)
                a := ir.Copy(n).(*ir.IndexExpr)
                a.X = l
                a.Index = r
-               return walkexpr(typecheck(a, ctxExpr), init)
+               return walkexpr(typecheck.Expr(a), init)
 
        case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
                n := n.(*ir.CompLitExpr)
 }
 
 func copyexpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
-       l := temp(t)
+       l := typecheck.Temp(t)
        appendWalkStmt(init, ir.NewAssignStmt(base.Pos, l, n))
        return l
 }
        return copyexpr(n, n.Type(), init)
 }
 
-// Code to resolve elided DOTs in embedded types.
-
-// A Dlist stores a pointer to a TFIELD Type embedded within
-// a TSTRUCT or TINTER Type.
-type Dlist struct {
-       field *types.Field
-}
-
-// dotlist is used by adddot1 to record the path of embedded fields
-// used to access a target field or method.
-// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
-var dotlist = make([]Dlist, 10)
-
-// lookdot0 returns the number of fields or methods named s associated
-// with Type t. If exactly one exists, it will be returned in *save
-// (if save is not nil).
-func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
-       u := t
-       if u.IsPtr() {
-               u = u.Elem()
-       }
-
-       c := 0
-       if u.IsStruct() || u.IsInterface() {
-               for _, f := range u.Fields().Slice() {
-                       if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
-                               if save != nil {
-                                       *save = f
-                               }
-                               c++
-                       }
-               }
-       }
-
-       u = t
-       if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() {
-               // If t is a defined pointer type, then x.m is shorthand for (*x).m.
-               u = t.Elem()
-       }
-       u = types.ReceiverBaseType(u)
-       if u != nil {
-               for _, f := range u.Methods().Slice() {
-                       if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
-                               if save != nil {
-                                       *save = f
-                               }
-                               c++
-                       }
-               }
-       }
-
-       return c
-}
-
-// adddot1 returns the number of fields or methods named s at depth d in Type t.
-// If exactly one exists, it will be returned in *save (if save is not nil),
-// and dotlist will contain the path of embedded fields traversed to find it,
-// in reverse order. If none exist, more will indicate whether t contains any
-// embedded fields at depth d, so callers can decide whether to retry at
-// a greater depth.
-func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
-       if t.Recur() {
-               return
-       }
-       t.SetRecur(true)
-       defer t.SetRecur(false)
-
-       var u *types.Type
-       d--
-       if d < 0 {
-               // We've reached our target depth. If t has any fields/methods
-               // named s, then we're done. Otherwise, we still need to check
-               // below for embedded fields.
-               c = lookdot0(s, t, save, ignorecase)
-               if c != 0 {
-                       return c, false
-               }
-       }
-
-       u = t
-       if u.IsPtr() {
-               u = u.Elem()
-       }
-       if !u.IsStruct() && !u.IsInterface() {
-               return c, false
-       }
-
-       for _, f := range u.Fields().Slice() {
-               if f.Embedded == 0 || f.Sym == nil {
-                       continue
-               }
-               if d < 0 {
-                       // Found an embedded field at target depth.
-                       return c, true
-               }
-               a, more1 := adddot1(s, f.Type, d, save, ignorecase)
-               if a != 0 && c == 0 {
-                       dotlist[d].field = f
-               }
-               c += a
-               if more1 {
-                       more = true
-               }
-       }
-
-       return c, more
-}
-
-// dotpath computes the unique shortest explicit selector path to fully qualify
-// a selection expression x.f, where x is of type t and f is the symbol s.
-// If no such path exists, dotpath returns nil.
-// If there are multiple shortest paths to the same depth, ambig is true.
-func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []Dlist, ambig bool) {
-       // The embedding of types within structs imposes a tree structure onto
-       // types: structs parent the types they embed, and types parent their
-       // fields or methods. Our goal here is to find the shortest path to
-       // a field or method named s in the subtree rooted at t. To accomplish
-       // that, we iteratively perform depth-first searches of increasing depth
-       // until we either find the named field/method or exhaust the tree.
-       for d := 0; ; d++ {
-               if d > len(dotlist) {
-                       dotlist = append(dotlist, Dlist{})
-               }
-               if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
-                       return dotlist[:d], false
-               } else if c > 1 {
-                       return nil, true
-               } else if !more {
-                       return nil, false
-               }
-       }
-}
-
-// in T.field
-// find missing fields that
-// will give shortest unique addressing.
-// modify the tree with missing type names.
-func adddot(n *ir.SelectorExpr) *ir.SelectorExpr {
-       n.X = typecheck(n.X, ctxType|ctxExpr)
-       if n.X.Diag() {
-               n.SetDiag(true)
-       }
-       t := n.X.Type()
-       if t == nil {
-               return n
-       }
-
-       if n.X.Op() == ir.OTYPE {
-               return n
-       }
-
-       s := n.Sel
-       if s == nil {
-               return n
-       }
-
-       switch path, ambig := dotpath(s, t, nil, false); {
-       case path != nil:
-               // rebuild elided dots
-               for c := len(path) - 1; c >= 0; c-- {
-                       dot := ir.NewSelectorExpr(base.Pos, ir.ODOT, n.X, path[c].field.Sym)
-                       dot.SetImplicit(true)
-                       dot.SetType(path[c].field.Type)
-                       n.X = dot
-               }
-       case ambig:
-               base.Errorf("ambiguous selector %v", n)
-               n.X = nil
-       }
-
-       return n
-}
-
-// Code to help generate trampoline functions for methods on embedded
-// types. These are approx the same as the corresponding adddot
-// routines except that they expect to be called with unique tasks and
-// they return the actual methods.
-
-type Symlink struct {
-       field *types.Field
-}
-
-var slist []Symlink
-
-func expand0(t *types.Type) {
-       u := t
-       if u.IsPtr() {
-               u = u.Elem()
-       }
-
-       if u.IsInterface() {
-               for _, f := range u.Fields().Slice() {
-                       if f.Sym.Uniq() {
-                               continue
-                       }
-                       f.Sym.SetUniq(true)
-                       slist = append(slist, Symlink{field: f})
-               }
-
-               return
-       }
-
-       u = types.ReceiverBaseType(t)
-       if u != nil {
-               for _, f := range u.Methods().Slice() {
-                       if f.Sym.Uniq() {
-                               continue
-                       }
-                       f.Sym.SetUniq(true)
-                       slist = append(slist, Symlink{field: f})
-               }
-       }
-}
-
-func expand1(t *types.Type, top bool) {
-       if t.Recur() {
-               return
-       }
-       t.SetRecur(true)
-
-       if !top {
-               expand0(t)
-       }
-
-       u := t
-       if u.IsPtr() {
-               u = u.Elem()
-       }
-
-       if u.IsStruct() || u.IsInterface() {
-               for _, f := range u.Fields().Slice() {
-                       if f.Embedded == 0 {
-                               continue
-                       }
-                       if f.Sym == nil {
-                               continue
-                       }
-                       expand1(f.Type, false)
-               }
-       }
-
-       t.SetRecur(false)
-}
-
-func expandmeth(t *types.Type) {
-       if t == nil || t.AllMethods().Len() != 0 {
-               return
-       }
-
-       // mark top-level method symbols
-       // so that expand1 doesn't consider them.
-       for _, f := range t.Methods().Slice() {
-               f.Sym.SetUniq(true)
-       }
-
-       // generate all reachable methods
-       slist = slist[:0]
-       expand1(t, true)
-
-       // check each method to be uniquely reachable
-       var ms []*types.Field
-       for i, sl := range slist {
-               slist[i].field = nil
-               sl.field.Sym.SetUniq(false)
-
-               var f *types.Field
-               path, _ := dotpath(sl.field.Sym, t, &f, false)
-               if path == nil {
-                       continue
-               }
-
-               // dotpath may have dug out arbitrary fields, we only want methods.
-               if !f.IsMethod() {
-                       continue
-               }
-
-               // add it to the base type method list
-               f = f.Copy()
-               f.Embedded = 1 // needs a trampoline
-               for _, d := range path {
-                       if d.field.Type.IsPtr() {
-                               f.Embedded = 2
-                               break
-                       }
-               }
-               ms = append(ms, f)
-       }
-
-       for _, f := range t.Methods().Slice() {
-               f.Sym.SetUniq(false)
-       }
-
-       ms = append(ms, t.Methods().Slice()...)
-       sort.Sort(types.MethodsByName(ms))
-       t.AllMethods().Set(ms)
-}
-
-// Given funarg struct list, return list of fn args.
-func structargs(tl *types.Type, mustname bool) []*ir.Field {
-       var args []*ir.Field
-       gen := 0
-       for _, t := range tl.Fields().Slice() {
-               s := t.Sym
-               if mustname && (s == nil || s.Name == "_") {
-                       // invent a name so that we can refer to it in the trampoline
-                       s = lookupN(".anon", gen)
-                       gen++
-               }
-               a := ir.NewField(base.Pos, s, nil, t.Type)
-               a.Pos = t.Pos
-               a.IsDDD = t.IsDDD()
-               args = append(args, a)
-       }
-
-       return args
-}
-
 // Generate a wrapper function to convert from
 // a receiver of type T to a receiver of type U.
 // That is,
        }
 
        base.Pos = base.AutogeneratedPos
-       dclcontext = ir.PEXTERN
+       typecheck.DeclContext = ir.PEXTERN
 
        tfn := ir.NewFuncType(base.Pos,
-               ir.NewField(base.Pos, lookup(".this"), nil, rcvr),
-               structargs(method.Type.Params(), true),
-               structargs(method.Type.Results(), false))
+               ir.NewField(base.Pos, typecheck.Lookup(".this"), nil, rcvr),
+               typecheck.NewFuncParams(method.Type.Params(), true),
+               typecheck.NewFuncParams(method.Type.Results(), false))
 
-       fn := dclfunc(newnam, tfn)
+       fn := typecheck.DeclFunc(newnam, tfn)
        fn.SetDupok(true)
 
        nthis := ir.AsNode(tfn.Type().Recv().Nname)
        if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
                // generating wrapper from *T to T.
                n := ir.NewIfStmt(base.Pos, nil, nil, nil)
-               n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, nodnil())
-               call := ir.NewCallExpr(base.Pos, ir.OCALL, syslook("panicwrap"), nil)
+               n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, typecheck.NodNil())
+               call := ir.NewCallExpr(base.Pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)
                n.Body = []ir.Node{call}
                fn.Body.Append(n)
        }
 
-       dot := adddot(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
+       dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
 
        // generate call
        // It's not possible to use a tail call when dynamic linking on ppc64le. The
                // generate tail call: adjust pointer receiver and jump to embedded method.
                left := dot.X // skip final .M
                if !left.Type().IsPtr() {
-                       left = nodAddr(left)
+                       left = typecheck.NodAddr(left)
                }
-               as := ir.NewAssignStmt(base.Pos, nthis, convnop(left, rcvr))
+               as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
                fn.Body.Append(as)
                fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.ORETJMP, ir.MethodSym(methodrcvr, method.Sym)))
        } else {
                ir.DumpList("genwrapper body", fn.Body)
        }
 
-       funcbody()
+       typecheck.FinishFuncBody()
        if base.Debug.DclStack != 0 {
                types.CheckDclstack()
        }
 
-       typecheckFunc(fn)
+       typecheck.Func(fn)
        ir.CurFunc = fn
-       typecheckslice(fn.Body, ctxStmt)
+       typecheck.Stmts(fn.Body)
 
        // Inline calls within (*T).M wrappers. This is safe because we only
        // generate those wrappers within the same compilation unit as (T).M.
        escapeFuncs([]*ir.Func{fn}, false)
 
        ir.CurFunc = nil
-       Target.Decls = append(Target.Decls, fn)
+       typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
 }
 
 func hashmem(t *types.Type) ir.Node {
        sym := ir.Pkgs.Runtime.Lookup("memhash")
 
-       n := NewName(sym)
+       n := typecheck.NewName(sym)
        ir.MarkFunc(n)
-       n.SetType(functype(nil, []*ir.Field{
+       n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
                ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
                ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
                ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
        return n
 }
 
-func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
-       if t == nil {
-               return nil, false
-       }
-
-       path, ambig := dotpath(s, t, &m, ignorecase)
-       if path == nil {
-               if ambig {
-                       base.Errorf("%v.%v is ambiguous", t, s)
-               }
-               return nil, false
-       }
-
-       for _, d := range path {
-               if d.field.Type.IsPtr() {
-                       followptr = true
-                       break
-               }
-       }
-
-       if !m.IsMethod() {
-               base.Errorf("%v.%v is a field, not a method", t, s)
-               return nil, followptr
-       }
-
-       return m, followptr
-}
-
-func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
-       t0 := t
-       if t == nil {
-               return false
-       }
-
-       if t.IsInterface() {
-               i := 0
-               tms := t.Fields().Slice()
-               for _, im := range iface.Fields().Slice() {
-                       for i < len(tms) && tms[i].Sym != im.Sym {
-                               i++
-                       }
-                       if i == len(tms) {
-                               *m = im
-                               *samename = nil
-                               *ptr = 0
-                               return false
-                       }
-                       tm := tms[i]
-                       if !types.Identical(tm.Type, im.Type) {
-                               *m = im
-                               *samename = tm
-                               *ptr = 0
-                               return false
-                       }
-               }
-
-               return true
-       }
-
-       t = types.ReceiverBaseType(t)
-       var tms []*types.Field
-       if t != nil {
-               expandmeth(t)
-               tms = t.AllMethods().Slice()
-       }
-       i := 0
-       for _, im := range iface.Fields().Slice() {
-               if im.Broke() {
-                       continue
-               }
-               for i < len(tms) && tms[i].Sym != im.Sym {
-                       i++
-               }
-               if i == len(tms) {
-                       *m = im
-                       *samename, _ = ifacelookdot(im.Sym, t, true)
-                       *ptr = 0
-                       return false
-               }
-               tm := tms[i]
-               if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
-                       *m = im
-                       *samename = tm
-                       *ptr = 0
-                       return false
-               }
-               followptr := tm.Embedded == 2
-
-               // if pointer receiver in method,
-               // the method does not exist for value types.
-               rcvr := tm.Type.Recv().Type
-               if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) {
-                       if false && base.Flag.LowerR != 0 {
-                               base.Errorf("interface pointer mismatch")
-                       }
-
-                       *m = im
-                       *samename = nil
-                       *ptr = 1
-                       return false
-               }
-       }
-
-       return true
-}
-
 func ngotype(n ir.Node) *types.Sym {
        if n.Type() != nil {
                return typenamesym(n.Type())
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
        "go/constant"
        "sort"
 )
 
-// typecheckswitch typechecks a switch statement.
-func typecheckswitch(n *ir.SwitchStmt) {
-       typecheckslice(n.Init(), ctxStmt)
-       if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
-               typecheckTypeSwitch(n)
-       } else {
-               typecheckExprSwitch(n)
-       }
-}
-
-func typecheckTypeSwitch(n *ir.SwitchStmt) {
-       guard := n.Tag.(*ir.TypeSwitchGuard)
-       guard.X = typecheck(guard.X, ctxExpr)
-       t := guard.X.Type()
-       if t != nil && !t.IsInterface() {
-               base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.X)
-               t = nil
-       }
-
-       // We don't actually declare the type switch's guarded
-       // declaration itself. So if there are no cases, we won't
-       // notice that it went unused.
-       if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
-               base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
-       }
-
-       var defCase, nilCase ir.Node
-       var ts typeSet
-       for _, ncase := range n.Cases {
-               ncase := ncase.(*ir.CaseStmt)
-               ls := ncase.List
-               if len(ls) == 0 { // default:
-                       if defCase != nil {
-                               base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
-                       } else {
-                               defCase = ncase
-                       }
-               }
-
-               for i := range ls {
-                       ls[i] = typecheck(ls[i], ctxExpr|ctxType)
-                       n1 := ls[i]
-                       if t == nil || n1.Type() == nil {
-                               continue
-                       }
-
-                       var missing, have *types.Field
-                       var ptr int
-                       if ir.IsNil(n1) { // case nil:
-                               if nilCase != nil {
-                                       base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
-                               } else {
-                                       nilCase = ncase
-                               }
-                               continue
-                       }
-                       if n1.Op() != ir.OTYPE {
-                               base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
-                               continue
-                       }
-                       if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
-                               if have != nil && !have.Broke() {
-                                       base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
-                                               " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
-                               } else if ptr != 0 {
-                                       base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
-                                               " (%v method has pointer receiver)", guard.X, n1.Type(), missing.Sym)
-                               } else {
-                                       base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
-                                               " (missing %v method)", guard.X, n1.Type(), missing.Sym)
-                               }
-                               continue
-                       }
-
-                       ts.add(ncase.Pos(), n1.Type())
-               }
-
-               if len(ncase.Vars) != 0 {
-                       // Assign the clause variable's type.
-                       vt := t
-                       if len(ls) == 1 {
-                               if ls[0].Op() == ir.OTYPE {
-                                       vt = ls[0].Type()
-                               } else if !ir.IsNil(ls[0]) {
-                                       // Invalid single-type case;
-                                       // mark variable as broken.
-                                       vt = nil
-                               }
-                       }
-
-                       nvar := ncase.Vars[0]
-                       nvar.SetType(vt)
-                       if vt != nil {
-                               nvar = typecheck(nvar, ctxExpr|ctxAssign)
-                       } else {
-                               // Clause variable is broken; prevent typechecking.
-                               nvar.SetTypecheck(1)
-                               nvar.SetWalkdef(1)
-                       }
-                       ncase.Vars[0] = nvar
-               }
-
-               typecheckslice(ncase.Body, ctxStmt)
-       }
-}
-
-type typeSet struct {
-       m map[string][]typeSetEntry
-}
-
-type typeSetEntry struct {
-       pos src.XPos
-       typ *types.Type
-}
-
-func (s *typeSet) add(pos src.XPos, typ *types.Type) {
-       if s.m == nil {
-               s.m = make(map[string][]typeSetEntry)
-       }
-
-       // LongString does not uniquely identify types, so we need to
-       // disambiguate collisions with types.Identical.
-       // TODO(mdempsky): Add a method that *is* unique.
-       ls := typ.LongString()
-       prevs := s.m[ls]
-       for _, prev := range prevs {
-               if types.Identical(typ, prev.typ) {
-                       base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
-                       return
-               }
-       }
-       s.m[ls] = append(prevs, typeSetEntry{pos, typ})
-}
-
-func typecheckExprSwitch(n *ir.SwitchStmt) {
-       t := types.Types[types.TBOOL]
-       if n.Tag != nil {
-               n.Tag = typecheck(n.Tag, ctxExpr)
-               n.Tag = defaultlit(n.Tag, nil)
-               t = n.Tag.Type()
-       }
-
-       var nilonly string
-       if t != nil {
-               switch {
-               case t.IsMap():
-                       nilonly = "map"
-               case t.Kind() == types.TFUNC:
-                       nilonly = "func"
-               case t.IsSlice():
-                       nilonly = "slice"
-
-               case !types.IsComparable(t):
-                       if t.IsStruct() {
-                               base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
-                       } else {
-                               base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
-                       }
-                       t = nil
-               }
-       }
-
-       var defCase ir.Node
-       var cs constSet
-       for _, ncase := range n.Cases {
-               ncase := ncase.(*ir.CaseStmt)
-               ls := ncase.List
-               if len(ls) == 0 { // default:
-                       if defCase != nil {
-                               base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
-                       } else {
-                               defCase = ncase
-                       }
-               }
-
-               for i := range ls {
-                       ir.SetPos(ncase)
-                       ls[i] = typecheck(ls[i], ctxExpr)
-                       ls[i] = defaultlit(ls[i], t)
-                       n1 := ls[i]
-                       if t == nil || n1.Type() == nil {
-                               continue
-                       }
-
-                       if nilonly != "" && !ir.IsNil(n1) {
-                               base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
-                       } else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
-                               base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
-                       } else {
-                               op1, _ := assignop(n1.Type(), t)
-                               op2, _ := assignop(t, n1.Type())
-                               if op1 == ir.OXXX && op2 == ir.OXXX {
-                                       if n.Tag != nil {
-                                               base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
-                                       } else {
-                                               base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
-                                       }
-                               }
-                       }
-
-                       // Don't check for duplicate bools. Although the spec allows it,
-                       // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
-                       // (2) it would disallow useful things like
-                       //       case GOARCH == "arm" && GOARM == "5":
-                       //       case GOARCH == "arm":
-                       //     which would both evaluate to false for non-ARM compiles.
-                       if !n1.Type().IsBoolean() {
-                               cs.add(ncase.Pos(), n1, "case", "switch")
-                       }
-               }
-
-               typecheckslice(ncase.Body, ctxStmt)
-       }
-}
-
 // walkswitch walks a switch statement.
 func walkswitch(sw *ir.SwitchStmt) {
        // Guard against double walk, see #25776.
        // convert switch {...} to switch true {...}
        if cond == nil {
                cond = ir.NewBool(true)
-               cond = typecheck(cond, ctxExpr)
-               cond = defaultlit(cond, nil)
+               cond = typecheck.Expr(cond)
+               cond = typecheck.DefaultLit(cond, nil)
        }
 
        // Given "switch string(byteslice)",
        var body ir.Nodes
        for _, ncase := range sw.Cases {
                ncase := ncase.(*ir.CaseStmt)
-               label := autolabel(".s")
+               label := typecheck.AutoLabel(".s")
                jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
 
                // Process case dispatch.
 
        s.facename = walkexpr(s.facename, sw.PtrInit())
        s.facename = copyexpr(s.facename, s.facename.Type(), &sw.Compiled)
-       s.okname = temp(types.Types[types.TBOOL])
+       s.okname = typecheck.Temp(types.Types[types.TBOOL])
 
        // Get interface descriptor word.
        // For empty interfaces this will be the type.
        //     h := e._type.hash
        // Use a similar strategy for non-empty interfaces.
        ifNil := ir.NewIfStmt(base.Pos, nil, nil, nil)
-       ifNil.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, itab, nodnil())
+       ifNil.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, itab, typecheck.NodNil())
        base.Pos = base.Pos.WithNotStmt() // disable statement marks after the first check.
-       ifNil.Cond = typecheck(ifNil.Cond, ctxExpr)
-       ifNil.Cond = defaultlit(ifNil.Cond, nil)
+       ifNil.Cond = typecheck.Expr(ifNil.Cond)
+       ifNil.Cond = typecheck.DefaultLit(ifNil.Cond, nil)
        // ifNil.Nbody assigned at end.
        sw.Compiled.Append(ifNil)
 
                }
                caseVarInitialized := false
 
-               label := autolabel(".s")
+               label := typecheck.AutoLabel(".s")
                jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
 
                if len(ncase.List) == 0 { // default:
                                ir.NewDecl(ncase.Pos(), ir.ODCL, caseVar),
                                ir.NewAssignStmt(ncase.Pos(), caseVar, val),
                        }
-                       typecheckslice(l, ctxStmt)
+                       typecheck.Stmts(l)
                        body.Append(l...)
                }
                body.Append(ncase.Body...)
                        ir.NewDecl(pos, ir.ODCL, caseVar),
                        ir.NewAssignStmt(pos, caseVar, nil),
                }
-               typecheckslice(l, ctxStmt)
+               typecheck.Stmts(l)
                body.Append(l...)
        } else {
                caseVar = ir.BlankNode
                                nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
                                leaf(i, nif)
                                base.Pos = base.Pos.WithNotStmt()
-                               nif.Cond = typecheck(nif.Cond, ctxExpr)
-                               nif.Cond = defaultlit(nif.Cond, nil)
+                               nif.Cond = typecheck.Expr(nif.Cond)
+                               nif.Cond = typecheck.DefaultLit(nif.Cond, nil)
                                out.Append(nif)
                                out = &nif.Else
                        }
                nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
                nif.Cond = less(half)
                base.Pos = base.Pos.WithNotStmt()
-               nif.Cond = typecheck(nif.Cond, ctxExpr)
-               nif.Cond = defaultlit(nif.Cond, nil)
+               nif.Cond = typecheck.Expr(nif.Cond)
+               nif.Cond = typecheck.DefaultLit(nif.Cond, nil)
                do(lo, half, &nif.Body)
                do(half, hi, &nif.Else)
                out.Append(nif)
 
+++ /dev/null
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements convertions between *types.Node and *Node.
-// TODO(gri) try to eliminate these soon
-
-package gc
 
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-)
-
-// evalunsafe evaluates a package unsafe operation and returns the result.
-func evalunsafe(n ir.Node) int64 {
-       switch n.Op() {
-       case ir.OALIGNOF, ir.OSIZEOF:
-               n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
-               tr := n.X.Type()
-               if tr == nil {
-                       return 0
-               }
-               types.CalcSize(tr)
-               if n.Op() == ir.OALIGNOF {
-                       return int64(tr.Align)
-               }
-               return tr.Width
-
-       case ir.OOFFSETOF:
-               // must be a selector.
-               n := n.(*ir.UnaryExpr)
-               if n.X.Op() != ir.OXDOT {
-                       base.Errorf("invalid expression %v", n)
-                       return 0
-               }
-               sel := n.X.(*ir.SelectorExpr)
-
-               // Remember base of selector to find it back after dot insertion.
-               // Since r->left may be mutated by typechecking, check it explicitly
-               // first to track it correctly.
-               sel.X = typecheck(sel.X, ctxExpr)
-               sbase := sel.X
-
-               tsel := typecheck(sel, ctxExpr)
-               n.X = tsel
-               if tsel.Type() == nil {
-                       return 0
-               }
-               switch tsel.Op() {
-               case ir.ODOT, ir.ODOTPTR:
-                       break
-               case ir.OCALLPART:
-                       base.Errorf("invalid expression %v: argument is a method value", n)
-                       return 0
-               default:
-                       base.Errorf("invalid expression %v", n)
-                       return 0
-               }
-
-               // Sum offsets for dots until we reach sbase.
-               var v int64
-               var next ir.Node
-               for r := tsel; r != sbase; r = next {
-                       switch r.Op() {
-                       case ir.ODOTPTR:
-                               // For Offsetof(s.f), s may itself be a pointer,
-                               // but accessing f must not otherwise involve
-                               // indirection via embedded pointer types.
-                               r := r.(*ir.SelectorExpr)
-                               if r.X != sbase {
-                                       base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.X)
-                                       return 0
-                               }
-                               fallthrough
-                       case ir.ODOT:
-                               r := r.(*ir.SelectorExpr)
-                               v += r.Offset
-                               next = r.X
-                       default:
-                               ir.Dump("unsafenmagic", tsel)
-                               base.Fatalf("impossible %v node after dot insertion", r.Op())
-                       }
-               }
-               return v
-       }
-
-       base.Fatalf("unexpected op %v", n.Op())
-       return 0
-}
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/objabi"
        // Final typecheck for any unused variables.
        for i, ln := range fn.Dcl {
                if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) {
-                       ln = typecheck(ln, ctxExpr|ctxAssign).(*ir.Name)
+                       ln = typecheck.AssignExpr(ln).(*ir.Name)
                        fn.Dcl[i] = ln
                }
        }
                n.PtrInit().Set(nil)
 
                n.X = walkexpr(n.X, &init)
-               call := walkexpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, nodnil()), &init)
+               call := walkexpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, typecheck.NodNil()), &init)
                return ir.InitExpr(init, call)
 
        case ir.OBREAK,
                        }
                        nn := ir.NewAssignStmt(base.Pos, v.Name().Heapaddr, callnew(v.Type()))
                        nn.Def = true
-                       return walkstmt(typecheck(nn, ctxStmt))
+                       return walkstmt(typecheck.Stmt(nn))
                }
                return n
 
                                if cl == ir.PPARAMOUT {
                                        var ln ir.Node = ln
                                        if ir.IsParamStackCopy(ln) {
-                                               ln = walkexpr(typecheck(ir.NewStarExpr(base.Pos, ln.Name().Heapaddr), ctxExpr), nil)
+                                               ln = walkexpr(typecheck.Expr(ir.NewStarExpr(base.Pos, ln.Name().Heapaddr)), nil)
                                        }
                                        rl = append(rl, ln)
                                }
                n := n.(*ir.Name)
                nn := ir.NewStarExpr(base.Pos, n.Name().Heapaddr)
                nn.X.MarkNonNil()
-               return walkexpr(typecheck(nn, ctxExpr), init)
+               return walkexpr(typecheck.Expr(nn), init)
        }
 
        n = walkexpr1(n, init)
        // walk of y%1 may have replaced it by 0.
        // Check whether n with its updated args is itself now a constant.
        t := n.Type()
-       n = evalConst(n)
+       n = typecheck.EvalConst(n)
        if n.Type() != t {
                base.Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type())
        }
        if n.Op() == ir.OLITERAL {
-               n = typecheck(n, ctxExpr)
+               n = typecheck.Expr(n)
                // Emit string symbol now to avoid emitting
                // any concurrently during the backend.
                if v := n.Val(); v.Kind() == constant.String {
                n := n.(*ir.UnaryExpr)
                if isRuneCount(n) {
                        // Replace len([]rune(string)) with runtime.countrunes(string).
-                       return mkcall("countrunes", n.Type(), init, conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
+                       return mkcall("countrunes", n.Type(), init, typecheck.Conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
                }
 
                n.X = walkexpr(n.X, init)
                }
                if t.IsArray() {
                        safeexpr(n.X, init)
-                       con := origIntConst(n, t.NumElem())
+                       con := typecheck.OrigInt(n, t.NumElem())
                        con.SetTypecheck(1)
                        return con
                }
 
        case ir.ORECOVER:
                n := n.(*ir.CallExpr)
-               return mkcall("gorecover", n.Type(), init, nodAddr(ir.RegFP))
+               return mkcall("gorecover", n.Type(), init, typecheck.NodAddr(ir.RegFP))
 
        case ir.OCLOSUREREAD, ir.OCFUNC:
                return n
 
                if n.Op() == ir.OASOP {
                        // Rewrite x op= y into x = x op y.
-                       n = ir.NewAssignStmt(base.Pos, left, typecheck(ir.NewBinaryExpr(base.Pos, n.(*ir.AssignOpStmt).AsOp, left, right), ctxExpr))
+                       n = ir.NewAssignStmt(base.Pos, left, typecheck.Expr(ir.NewBinaryExpr(base.Pos, n.(*ir.AssignOpStmt).AsOp, left, right)))
                } else {
                        n.(*ir.AssignStmt).X = left
                }
                        recv := as.Y.(*ir.UnaryExpr)
                        recv.X = walkexpr(recv.X, init)
 
-                       n1 := nodAddr(as.X)
+                       n1 := typecheck.NodAddr(as.X)
                        r := recv.X // the channel
                        return mkcall1(chanfn("chanrecv1", 2, r.Type()), nil, init, r, n1)
 
                r.X = walkexpr(r.X, init)
                var n1 ir.Node
                if ir.IsBlank(n.Lhs[0]) {
-                       n1 = nodnil()
+                       n1 = typecheck.NodNil()
                } else {
-                       n1 = nodAddr(n.Lhs[0])
+                       n1 = typecheck.NodAddr(n.Lhs[0])
                }
                fn := chanfn("chanrecv2", 2, r.X.Type())
                ok := n.Lhs[1]
                call := mkcall1(fn, types.Types[types.TBOOL], init, r.X, n1)
-               return typecheck(ir.NewAssignStmt(base.Pos, ok, call), ctxStmt)
+               return typecheck.Stmt(ir.NewAssignStmt(base.Pos, ok, call))
 
        // a,b = m[i]
        case ir.OAS2MAPR:
                } else {
                        // standard version takes key by reference
                        // order.expr made sure key is addressable.
-                       key = nodAddr(r.Index)
+                       key = typecheck.NodAddr(r.Index)
                }
 
                // from:
 
                // don't generate a = *var if a is _
                if ir.IsBlank(a) {
-                       return walkexpr(typecheck(n, ctxStmt), init)
+                       return walkexpr(typecheck.Stmt(n), init)
                }
 
-               var_ := temp(types.NewPtr(t.Elem()))
+               var_ := typecheck.Temp(types.NewPtr(t.Elem()))
                var_.SetTypecheck(1)
                var_.MarkNonNil() // mapaccess always returns a non-nil pointer
 
                init.Append(walkexpr(n, init))
 
                as := ir.NewAssignStmt(base.Pos, a, ir.NewStarExpr(base.Pos, var_))
-               return walkexpr(typecheck(as, ctxStmt), init)
+               return walkexpr(typecheck.Stmt(as), init)
 
        case ir.ODELETE:
                n := n.(*ir.CallExpr)
                fast := mapfast(t)
                if fast == mapslow {
                        // order.stmt made sure key is addressable.
-                       key = nodAddr(key)
+                       key = typecheck.NodAddr(key)
                }
                return mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
 
                }
 
                if ir.Names.Staticuint64s == nil {
-                       ir.Names.Staticuint64s = NewName(ir.Pkgs.Runtime.Lookup("staticuint64s"))
+                       ir.Names.Staticuint64s = typecheck.NewName(ir.Pkgs.Runtime.Lookup("staticuint64s"))
                        ir.Names.Staticuint64s.Class_ = ir.PEXTERN
                        // The actual type is [256]uint64, but we use [256*8]uint8 so we can address
                        // individual bytes.
                        ir.Names.Staticuint64s.SetType(types.NewArray(types.Types[types.TUINT8], 256*8))
-                       ir.Names.Zerobase = NewName(ir.Pkgs.Runtime.Lookup("zerobase"))
+                       ir.Names.Zerobase = typecheck.NewName(ir.Pkgs.Runtime.Lookup("zerobase"))
                        ir.Names.Zerobase.Class_ = ir.PEXTERN
                        ir.Names.Zerobase.SetType(types.Types[types.TUINTPTR])
                }
                        value = n.X
                case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024:
                        // n.Left does not escape. Use a stack temporary initialized to n.Left.
-                       value = temp(fromType)
-                       init.Append(typecheck(ir.NewAssignStmt(base.Pos, value, n.X), ctxStmt))
+                       value = typecheck.Temp(fromType)
+                       init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n.X)))
                }
 
                if value != nil {
                        // Value is identical to n.Left.
                        // Construct the interface directly: {type/itab, &value}.
-                       l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck(nodAddr(value), ctxExpr))
+                       l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck.Expr(typecheck.NodAddr(value)))
                        l.SetType(toType)
                        l.SetTypecheck(n.Typecheck())
                        return l
                // e = iface{tmp, i.data}
                if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
                        // Evaluate the input interface.
-                       c := temp(fromType)
+                       c := typecheck.Temp(fromType)
                        init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
 
                        // Get the itab out of the interface.
-                       tmp := temp(types.NewPtr(types.Types[types.TUINT8]))
-                       init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck(ir.NewUnaryExpr(base.Pos, ir.OITAB, c), ctxExpr)))
+                       tmp := typecheck.Temp(types.NewPtr(types.Types[types.TUINT8]))
+                       init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, c))))
 
                        // Get the type out of the itab.
-                       nif := ir.NewIfStmt(base.Pos, typecheck(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, nodnil()), ctxExpr), nil, nil)
+                       nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, typecheck.NodNil())), nil, nil)
                        nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, tmp, itabType(tmp))}
                        init.Append(nif)
 
                        // Use a specialized conversion routine that only returns a data pointer.
                        // ptr = convT2X(val)
                        // e = iface{typ/tab, ptr}
-                       fn := syslook(fnname)
+                       fn := typecheck.LookupRuntime(fnname)
                        types.CalcSize(fromType)
-                       fn = substArgTypes(fn, fromType)
+                       fn = typecheck.SubstArgTypes(fn, fromType)
                        types.CalcSize(fn.Type())
                        call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
                        call.Args = []ir.Node{n.X}
-                       e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeexpr(walkexpr(typecheck(call, ctxExpr), init), init))
+                       e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeexpr(walkexpr(typecheck.Expr(call), init), init))
                        e.SetType(toType)
                        e.SetTypecheck(1)
                        return e
                        if !ir.IsAssignable(v) {
                                v = copyexpr(v, v.Type(), init)
                        }
-                       v = nodAddr(v)
+                       v = typecheck.NodAddr(v)
                }
 
                types.CalcSize(fromType)
-               fn := syslook(fnname)
-               fn = substArgTypes(fn, fromType, toType)
+               fn := typecheck.LookupRuntime(fnname)
+               fn = typecheck.SubstArgTypes(fn, fromType, toType)
                types.CalcSize(fn.Type())
                call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
                call.Args = []ir.Node{tab, v}
-               return walkexpr(typecheck(call, ctxExpr), init)
+               return walkexpr(typecheck.Expr(call), init)
 
        case ir.OCONV, ir.OCONVNOP:
                n := n.(*ir.ConvExpr)
                        return n
                }
                fn := types.BasicTypeNames[param] + "to" + types.BasicTypeNames[result]
-               return conv(mkcall(fn, types.Types[result], init, conv(n.X, types.Types[param])), n.Type())
+               return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type())
 
        case ir.ODIV, ir.OMOD:
                n := n.(*ir.BinaryExpr)
 
                if types.IsComplex[et] && n.Op() == ir.ODIV {
                        t := n.Type()
-                       call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, conv(n.X, types.Types[types.TCOMPLEX128]), conv(n.Y, types.Types[types.TCOMPLEX128]))
-                       return conv(call, t)
+                       call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, typecheck.Conv(n.X, types.Types[types.TCOMPLEX128]), typecheck.Conv(n.Y, types.Types[types.TCOMPLEX128]))
+                       return typecheck.Conv(call, t)
                }
 
                // Nothing to do for float divisions.
                        } else {
                                fn += "mod"
                        }
-                       return mkcall(fn, n.Type(), init, conv(n.X, types.Types[et]), conv(n.Y, types.Types[et]))
+                       return mkcall(fn, n.Type(), init, typecheck.Conv(n.X, types.Types[et]), typecheck.Conv(n.Y, types.Types[et]))
                }
                return n
 
                        if fast == mapslow {
                                // standard version takes key by reference.
                                // order.expr made sure key is addressable.
-                               key = nodAddr(key)
+                               key = typecheck.NodAddr(key)
                        }
                        call = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)
                } else {
                        if fast == mapslow {
                                // standard version takes key by reference.
                                // order.expr made sure key is addressable.
-                               key = nodAddr(key)
+                               key = typecheck.NodAddr(key)
                        }
 
                        if w := t.Elem().Width; w <= zeroValSize {
                        if n.Type().Elem().Width >= ir.MaxImplicitStackVarSize {
                                base.Fatalf("large ONEW with EscNone: %v", n)
                        }
-                       r := temp(n.Type().Elem())
-                       init.Append(typecheck(ir.NewAssignStmt(base.Pos, r, nil), ctxStmt)) // zero temp
-                       return typecheck(nodAddr(r), ctxExpr)
+                       r := typecheck.Temp(n.Type().Elem())
+                       init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, nil))) // zero temp
+                       return typecheck.Expr(typecheck.NodAddr(r))
                }
                return callnew(n.Type().Elem())
 
        case ir.OCLOSE:
                // cannot use chanfn - closechan takes any, not chan any
                n := n.(*ir.UnaryExpr)
-               fn := syslook("closechan")
-               fn = substArgTypes(fn, n.X.Type())
+               fn := typecheck.LookupRuntime("closechan")
+               fn = typecheck.SubstArgTypes(fn, n.X.Type())
                return mkcall1(fn, nil, init, n.X)
 
        case ir.OMAKECHAN:
                        argtype = types.Types[types.TINT]
                }
 
-               return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), conv(size, argtype))
+               return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), typecheck.Conv(size, argtype))
 
        case ir.OMAKEMAP:
                n := n.(*ir.MakeExpr)
                        // Allocate hmap on stack.
 
                        // var hv hmap
-                       hv := temp(hmapType)
-                       init.Append(typecheck(ir.NewAssignStmt(base.Pos, hv, nil), ctxStmt))
+                       hv := typecheck.Temp(hmapType)
+                       init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, hv, nil)))
                        // h = &hv
-                       h = nodAddr(hv)
+                       h = typecheck.NodAddr(hv)
 
                        // Allocate one bucket pointed to by hmap.buckets on stack if hint
                        // is not larger than BUCKETSIZE. In case hint is larger than
                                nif.Likely = true
 
                                // var bv bmap
-                               bv := temp(bmap(t))
+                               bv := typecheck.Temp(bmap(t))
                                nif.Body.Append(ir.NewAssignStmt(base.Pos, bv, nil))
 
                                // b = &bv
-                               b := nodAddr(bv)
+                               b := typecheck.NodAddr(bv)
 
                                // h.buckets = b
                                bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
                                rand := mkcall("fastrand", types.Types[types.TUINT32], init)
                                hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap
                                appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, hashsym), rand))
-                               return convnop(h, t)
+                               return typecheck.ConvNop(h, t)
                        }
                        // Call runtime.makehmap to allocate an
                        // hmap on the heap and initialize hmap's hash0 field.
-                       fn := syslook("makemap_small")
-                       fn = substArgTypes(fn, t.Key(), t.Elem())
+                       fn := typecheck.LookupRuntime("makemap_small")
+                       fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
                        return mkcall1(fn, n.Type(), init)
                }
 
                if n.Esc() != ir.EscNone {
-                       h = nodnil()
+                       h = typecheck.NodNil()
                }
                // Map initialization with a variable or large hint is
                // more complicated. We therefore generate a call to
                        argtype = types.Types[types.TINT]
                }
 
-               fn := syslook(fnname)
-               fn = substArgTypes(fn, hmapType, t.Key(), t.Elem())
-               return mkcall1(fn, n.Type(), init, typename(n.Type()), conv(hint, argtype), h)
+               fn := typecheck.LookupRuntime(fnname)
+               fn = typecheck.SubstArgTypes(fn, hmapType, t.Key(), t.Elem())
+               return mkcall1(fn, n.Type(), init, typename(n.Type()), typecheck.Conv(hint, argtype), h)
 
        case ir.OMAKESLICE:
                n := n.(*ir.MakeExpr)
                        }
                        // var arr [r]T
                        // n = arr[:l]
-                       i := indexconst(r)
+                       i := typecheck.IndexConst(r)
                        if i < 0 {
                                base.Fatalf("walkexpr: invalid index %v", r)
                        }
                        //     if len < 0 { panicmakeslicelen() }
                        //     panicmakeslicecap()
                        // }
-                       nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, conv(l, types.Types[types.TUINT64]), ir.NewInt(i)), nil, nil)
+                       nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(l, types.Types[types.TUINT64]), ir.NewInt(i)), nil, nil)
                        niflen := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, l, ir.NewInt(0)), nil, nil)
                        niflen.Body = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
                        nif.Body.Append(niflen, mkcall("panicmakeslicecap", nil, init))
-                       init.Append(typecheck(nif, ctxStmt))
+                       init.Append(typecheck.Stmt(nif))
 
                        t = types.NewArray(t.Elem(), i) // [r]T
-                       var_ := temp(t)
+                       var_ := typecheck.Temp(t)
                        appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil)) // zero temp
                        r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_)             // arr[:l]
                        r.SetSliceBounds(nil, l, nil)
                        // The conv is necessary in case n.Type is named.
-                       return walkexpr(typecheck(conv(r, n.Type()), ctxExpr), init)
+                       return walkexpr(typecheck.Expr(typecheck.Conv(r, n.Type())), init)
                }
 
                // n escapes; set up a call to makeslice.
                m := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
                m.SetType(t)
 
-               fn := syslook(fnname)
-               m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
+               fn := typecheck.LookupRuntime(fnname)
+               m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
                m.Ptr.MarkNonNil()
-               m.LenCap = []ir.Node{conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT])}
-               return walkexpr(typecheck(m, ctxExpr), init)
+               m.LenCap = []ir.Node{typecheck.Conv(len, types.Types[types.TINT]), typecheck.Conv(cap, types.Types[types.TINT])}
+               return walkexpr(typecheck.Expr(m), init)
 
        case ir.OMAKESLICECOPY:
                n := n.(*ir.MakeExpr)
                        base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
                }
 
-               length := conv(n.Len, types.Types[types.TINT])
+               length := typecheck.Conv(n.Len, types.Types[types.TINT])
                copylen := ir.NewUnaryExpr(base.Pos, ir.OLEN, n.Cap)
                copyptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, n.Cap)
 
                        // We do not check for overflow of len(to)*elem.Width here
                        // since len(from) is an existing checked slice capacity
                        // with same elem.Width for the from slice.
-                       size := ir.NewBinaryExpr(base.Pos, ir.OMUL, conv(length, types.Types[types.TUINTPTR]), conv(ir.NewInt(t.Elem().Width), types.Types[types.TUINTPTR]))
+                       size := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(t.Elem().Width), types.Types[types.TUINTPTR]))
 
                        // instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
-                       fn := syslook("mallocgc")
+                       fn := typecheck.LookupRuntime("mallocgc")
                        sh := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
-                       sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, nodnil(), ir.NewBool(false))
+                       sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(false))
                        sh.Ptr.MarkNonNil()
                        sh.LenCap = []ir.Node{length, length}
                        sh.SetType(t)
 
-                       s := temp(t)
-                       r := typecheck(ir.NewAssignStmt(base.Pos, s, sh), ctxStmt)
+                       s := typecheck.Temp(t)
+                       r := typecheck.Stmt(ir.NewAssignStmt(base.Pos, s, sh))
                        r = walkexpr(r, init)
                        init.Append(r)
 
                        // instantiate memmove(to *any, frm *any, size uintptr)
-                       fn = syslook("memmove")
-                       fn = substArgTypes(fn, t.Elem(), t.Elem())
+                       fn = typecheck.LookupRuntime("memmove")
+                       fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
                        ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size)
-                       init.Append(walkexpr(typecheck(ncopy, ctxStmt), init))
+                       init.Append(walkexpr(typecheck.Stmt(ncopy), init))
 
                        return s
                }
                // Replace make+copy with runtime.makeslicecopy.
                // instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
-               fn := syslook("makeslicecopy")
+               fn := typecheck.LookupRuntime("makeslicecopy")
                s := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
-               s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[types.TUNSAFEPTR]))
+               s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
                s.Ptr.MarkNonNil()
                s.LenCap = []ir.Node{length, length}
                s.SetType(t)
-               return walkexpr(typecheck(s, ctxExpr), init)
+               return walkexpr(typecheck.Expr(s), init)
 
        case ir.ORUNESTR:
                n := n.(*ir.ConvExpr)
-               a := nodnil()
+               a := typecheck.NodNil()
                if n.Esc() == ir.EscNone {
                        t := types.NewArray(types.Types[types.TUINT8], 4)
-                       a = nodAddr(temp(t))
+                       a = typecheck.NodAddr(typecheck.Temp(t))
                }
                // intstring(*[4]byte, rune)
-               return mkcall("intstring", n.Type(), init, a, conv(n.X, types.Types[types.TINT64]))
+               return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
 
        case ir.OBYTES2STR, ir.ORUNES2STR:
                n := n.(*ir.ConvExpr)
-               a := nodnil()
+               a := typecheck.NodNil()
                if n.Esc() == ir.EscNone {
                        // Create temporary buffer for string on stack.
                        t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
-                       a = nodAddr(temp(t))
+                       a = typecheck.NodAddr(typecheck.Temp(t))
                }
                if n.Op() == ir.ORUNES2STR {
                        // slicerunetostring(*[32]byte, []rune) string
                        t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
                        var a ir.Node
                        if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
-                               a = nodAddr(temp(t))
+                               a = typecheck.NodAddr(typecheck.Temp(t))
                        } else {
                                a = callnew(t)
                        }
-                       p := temp(t.PtrTo()) // *[n]byte
-                       init.Append(typecheck(ir.NewAssignStmt(base.Pos, p, a), ctxStmt))
+                       p := typecheck.Temp(t.PtrTo()) // *[n]byte
+                       init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
 
                        // Copy from the static string data to the [n]byte.
                        if len(sc) > 0 {
-                               as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, convnop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo())))
+                               as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo())))
                                appendWalkStmt(init, as)
                        }
 
                        return walkexpr(slice, init)
                }
 
-               a := nodnil()
+               a := typecheck.NodNil()
                if n.Esc() == ir.EscNone {
                        // Create temporary buffer for slice on stack.
                        t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
-                       a = nodAddr(temp(t))
+                       a = typecheck.NodAddr(typecheck.Temp(t))
                }
                // stringtoslicebyte(*32[byte], string) []byte
-               return mkcall("stringtoslicebyte", n.Type(), init, a, conv(s, types.Types[types.TSTRING]))
+               return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
 
        case ir.OSTR2BYTESTMP:
                // []byte(string) conversion that creates a slice
 
        case ir.OSTR2RUNES:
                n := n.(*ir.ConvExpr)
-               a := nodnil()
+               a := typecheck.NodNil()
                if n.Esc() == ir.EscNone {
                        // Create temporary buffer for slice on stack.
                        t := types.NewArray(types.Types[types.TINT32], tmpstringbufsize)
-                       a = nodAddr(temp(t))
+                       a = typecheck.NodAddr(typecheck.Temp(t))
                }
                // stringtoslicerune(*[32]rune, string) []rune
-               return mkcall("stringtoslicerune", n.Type(), init, a, conv(n.X, types.Types[types.TSTRING]))
+               return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
 
        case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT, ir.OPTRLIT:
                if isStaticCompositeLiteral(n) && !canSSAType(n.Type()) {
                        // Make direct reference to the static data. See issue 12841.
                        vstat := readonlystaticname(n.Type())
                        fixedlit(inInitFunction, initKindStatic, n, vstat, init)
-                       return typecheck(vstat, ctxExpr)
+                       return typecheck.Expr(vstat)
                }
-               var_ := temp(n.Type())
+               var_ := typecheck.Temp(n.Type())
                anylit(n, var_, init)
                return var_
 
        case ir.OSEND:
                n := n.(*ir.SendStmt)
                n1 := n.Value
-               n1 = assignconv(n1, n.Chan.Type().Elem(), "chan send")
+               n1 = typecheck.AssignConv(n1, n.Chan.Type().Elem(), "chan send")
                n1 = walkexpr(n1, init)
-               n1 = nodAddr(n1)
+               n1 = typecheck.NodAddr(n1)
                return mkcall1(chanfn("chansend1", 2, n.Chan.Type()), nil, init, n.Chan, n1)
 
        case ir.OCLOSURE:
                // Any assignment to an lvalue that might cause a function call must be
                // deferred until all the returned values have been read.
                if fncall(l, r.Type) {
-                       tmp := ir.Node(temp(r.Type))
-                       tmp = typecheck(tmp, ctxExpr)
+                       tmp := ir.Node(typecheck.Temp(r.Type))
+                       tmp = typecheck.Expr(tmp)
                        a := convas(ir.NewAssignStmt(base.Pos, l, tmp), &mm)
                        mm.Append(a)
                        l = tmp
        return append(nn, mm...)
 }
 
-// package all the arguments that match a ... T parameter into a []T.
-func mkdotargslice(typ *types.Type, args []ir.Node) ir.Node {
-       var n ir.Node
-       if len(args) == 0 {
-               n = nodnil()
-               n.SetType(typ)
-       } else {
-               lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
-               lit.List.Append(args...)
-               lit.SetImplicit(true)
-               n = lit
-       }
-
-       n = typecheck(n, ctxExpr)
-       if n.Type() == nil {
-               base.Fatalf("mkdotargslice: typecheck failed")
-       }
-       return n
-}
-
-// fixVariadicCall rewrites calls to variadic functions to use an
-// explicit ... argument if one is not already present.
-func fixVariadicCall(call *ir.CallExpr) {
-       fntype := call.X.Type()
-       if !fntype.IsVariadic() || call.IsDDD {
-               return
-       }
-
-       vi := fntype.NumParams() - 1
-       vt := fntype.Params().Field(vi).Type
-
-       args := call.Args
-       extra := args[vi:]
-       slice := mkdotargslice(vt, extra)
-       for i := range extra {
-               extra[i] = nil // allow GC
-       }
-
-       call.Args.Set(append(args[:vi], slice))
-       call.IsDDD = true
-}
-
 func walkCall(n *ir.CallExpr, init *ir.Nodes) {
        if len(n.Rargs) != 0 {
                return // already walked
                }
                if base.Flag.Cfg.Instrumenting || fncall(arg, t) {
                        // make assignment of fncall to tempAt
-                       tmp := temp(t)
+                       tmp := typecheck.Temp(t)
                        a := convas(ir.NewAssignStmt(base.Pos, tmp, arg), init)
                        tempAssigns = append(tempAssigns, a)
                        // replace arg with temp
        for i, n := range nn.Args {
                if n.Op() == ir.OLITERAL {
                        if n.Type() == types.UntypedRune {
-                               n = defaultlit(n, types.RuneType)
+                               n = typecheck.DefaultLit(n, types.RuneType)
                        }
 
                        switch n.Val().Kind() {
                        case constant.Int:
-                               n = defaultlit(n, types.Types[types.TINT64])
+                               n = typecheck.DefaultLit(n, types.Types[types.TINT64])
 
                        case constant.Float:
-                               n = defaultlit(n, types.Types[types.TFLOAT64])
+                               n = typecheck.DefaultLit(n, types.Types[types.TFLOAT64])
                        }
                }
 
                if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
-                       n = defaultlit(n, types.Types[types.TINT64])
+                       n = typecheck.DefaultLit(n, types.Types[types.TINT64])
                }
-               n = defaultlit(n, nil)
+               n = typecheck.DefaultLit(n, nil)
                nn.Args[i] = n
                if n.Type() == nil || n.Type().Kind() == types.TFORW {
                        continue
                switch n.Type().Kind() {
                case types.TINTER:
                        if n.Type().IsEmptyInterface() {
-                               on = syslook("printeface")
+                               on = typecheck.LookupRuntime("printeface")
                        } else {
-                               on = syslook("printiface")
+                               on = typecheck.LookupRuntime("printiface")
                        }
-                       on = substArgTypes(on, n.Type()) // any-1
+                       on = typecheck.SubstArgTypes(on, n.Type()) // any-1
                case types.TPTR:
                        if n.Type().Elem().NotInHeap() {
-                               on = syslook("printuintptr")
+                               on = typecheck.LookupRuntime("printuintptr")
                                n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
                                n.SetType(types.Types[types.TUNSAFEPTR])
                                n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
                        }
                        fallthrough
                case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
-                       on = syslook("printpointer")
-                       on = substArgTypes(on, n.Type()) // any-1
+                       on = typecheck.LookupRuntime("printpointer")
+                       on = typecheck.SubstArgTypes(on, n.Type()) // any-1
                case types.TSLICE:
-                       on = syslook("printslice")
-                       on = substArgTypes(on, n.Type()) // any-1
+                       on = typecheck.LookupRuntime("printslice")
+                       on = typecheck.SubstArgTypes(on, n.Type()) // any-1
                case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
                        if types.IsRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
-                               on = syslook("printhex")
+                               on = typecheck.LookupRuntime("printhex")
                        } else {
-                               on = syslook("printuint")
+                               on = typecheck.LookupRuntime("printuint")
                        }
                case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64:
-                       on = syslook("printint")
+                       on = typecheck.LookupRuntime("printint")
                case types.TFLOAT32, types.TFLOAT64:
-                       on = syslook("printfloat")
+                       on = typecheck.LookupRuntime("printfloat")
                case types.TCOMPLEX64, types.TCOMPLEX128:
-                       on = syslook("printcomplex")
+                       on = typecheck.LookupRuntime("printcomplex")
                case types.TBOOL:
-                       on = syslook("printbool")
+                       on = typecheck.LookupRuntime("printbool")
                case types.TSTRING:
                        cs := ""
                        if ir.IsConst(n, constant.String) {
                        }
                        switch cs {
                        case " ":
-                               on = syslook("printsp")
+                               on = typecheck.LookupRuntime("printsp")
                        case "\n":
-                               on = syslook("printnl")
+                               on = typecheck.LookupRuntime("printnl")
                        default:
-                               on = syslook("printstring")
+                               on = typecheck.LookupRuntime("printstring")
                        }
                default:
                        badtype(ir.OPRINT, n.Type(), nil)
 
        calls = append(calls, mkcall("printunlock", nil, init))
 
-       typecheckslice(calls, ctxStmt)
+       typecheck.Stmts(calls)
        walkexprlist(calls, init)
 
        r := ir.NewBlockStmt(base.Pos, nil)
        r.List.Set(calls)
-       return walkstmt(typecheck(r, ctxStmt))
+       return walkstmt(typecheck.Stmt(r))
 }
 
 func callnew(t *types.Type) ir.Node {
        }
 
        if ir.IsBlank(n.X) {
-               n.Y = defaultlit(n.Y, nil)
+               n.Y = typecheck.DefaultLit(n.Y, nil)
                return n
        }
 
        if !types.Identical(lt, rt) {
-               n.Y = assignconv(n.Y, lt, "assignment")
+               n.Y = typecheck.AssignConv(n.Y, lt, "assignment")
                n.Y = walkexpr(n.Y, init)
        }
        types.CalcSize(n.Y.Type())
                return n
        }
 
-       q := ir.Node(temp(n.Type()))
-       as := typecheck(ir.NewAssignStmt(base.Pos, q, n), ctxStmt)
+       q := ir.Node(typecheck.Temp(n.Type()))
+       as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, q, n))
        *early = append(*early, as)
        return q
 }
                if stackcopy := v.Name().Stackcopy; stackcopy != nil {
                        nn = append(nn, walkstmt(ir.NewDecl(base.Pos, ir.ODCL, v)))
                        if stackcopy.Class_ == ir.PPARAM {
-                               nn = append(nn, walkstmt(typecheck(ir.NewAssignStmt(base.Pos, v, stackcopy), ctxStmt)))
+                               nn = append(nn, walkstmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, v, stackcopy))))
                        }
                }
        }
                        continue
                }
                if stackcopy := v.Name().Stackcopy; stackcopy != nil && stackcopy.Class_ == ir.PPARAMOUT {
-                       nn = append(nn, walkstmt(typecheck(ir.NewAssignStmt(base.Pos, stackcopy, v), ctxStmt)))
+                       nn = append(nn, walkstmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, stackcopy, v))))
                }
        }
 
        }
 
        call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, va)
-       TypecheckCall(call)
+       typecheck.Call(call)
        call.SetType(t)
        return walkexpr(call, init).(*ir.CallExpr)
 }
 
 func mkcall(name string, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
-       return vmkcall(syslook(name), t, init, args)
+       return vmkcall(typecheck.LookupRuntime(name), t, init, args)
 }
 
 func mkcall1(fn ir.Node, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
        return vmkcall(fn, t, init, args)
 }
 
-func conv(n ir.Node, t *types.Type) ir.Node {
-       if types.Identical(n.Type(), t) {
-               return n
-       }
-       n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
-       n.SetType(t)
-       n = typecheck(n, ctxExpr)
-       return n
-}
-
-// convnop converts node n to type t using the OCONVNOP op
-// and typechecks the result with ctxExpr.
-func convnop(n ir.Node, t *types.Type) ir.Node {
-       if types.Identical(n.Type(), t) {
-               return n
-       }
-       n = ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
-       n.SetType(t)
-       n = typecheck(n, ctxExpr)
-       return n
-}
-
 // byteindex converts n, which is byte-sized, to an int used to index into an array.
 // We cannot use conv, because we allow converting bool to int here,
 // which is forbidden in user code.
        if !t.IsChan() {
                base.Fatalf("chanfn %v", t)
        }
-       fn := syslook(name)
+       fn := typecheck.LookupRuntime(name)
        switch n {
        default:
                base.Fatalf("chanfn %d", n)
        case 1:
-               fn = substArgTypes(fn, t.Elem())
+               fn = typecheck.SubstArgTypes(fn, t.Elem())
        case 2:
-               fn = substArgTypes(fn, t.Elem(), t.Elem())
+               fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
        }
        return fn
 }
        if !t.IsMap() {
                base.Fatalf("mapfn %v", t)
        }
-       fn := syslook(name)
-       fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem())
+       fn := typecheck.LookupRuntime(name)
+       fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem())
        return fn
 }
 
        if !t.IsMap() {
                base.Fatalf("mapfn %v", t)
        }
-       fn := syslook(name)
-       fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key())
+       fn := typecheck.LookupRuntime(name)
+       fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Key())
        return fn
 }
 
 }
 
 func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node {
-       fn := syslook(name)
-       fn = substArgTypes(fn, l, r)
+       fn := typecheck.LookupRuntime(name)
+       fn = typecheck.SubstArgTypes(fn, l, r)
        return fn
 }
 
                base.Fatalf("addstr count %d too small", c)
        }
 
-       buf := nodnil()
+       buf := typecheck.NodNil()
        if n.Esc() == ir.EscNone {
                sz := int64(0)
                for _, n1 := range n.List {
                if sz < tmpstringbufsize {
                        // Create temporary buffer for result string on stack.
                        t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
-                       buf = nodAddr(temp(t))
+                       buf = typecheck.NodAddr(typecheck.Temp(t))
                }
        }
 
        // build list of string arguments
        args := []ir.Node{buf}
        for _, n2 := range n.List {
-               args = append(args, conv(n2, types.Types[types.TSTRING]))
+               args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING]))
        }
 
        var fn string
                slice.SetEsc(ir.EscNone)
        }
 
-       cat := syslook(fn)
+       cat := typecheck.LookupRuntime(fn)
        r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil)
        r.Args.Set(args)
-       r1 := typecheck(r, ctxExpr)
+       r1 := typecheck.Expr(r)
        r1 = walkexpr(r1, init)
        r1.SetType(n.Type())
 
        var nodes ir.Nodes
 
        // var s []T
-       s := temp(l1.Type())
+       s := typecheck.Temp(l1.Type())
        nodes.Append(ir.NewAssignStmt(base.Pos, s, l1)) // s = l1
 
        elemtype := s.Type().Elem()
 
        // n := len(s) + len(l2)
-       nn := temp(types.Types[types.TINT])
+       nn := typecheck.Temp(types.Types[types.TINT])
        nodes.Append(ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), ir.NewUnaryExpr(base.Pos, ir.OLEN, l2))))
 
        // if uint(n) > uint(cap(s))
        nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
-       nuint := conv(nn, types.Types[types.TUINT])
-       scapuint := conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
+       nuint := typecheck.Conv(nn, types.Types[types.TUINT])
+       scapuint := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
        nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, nuint, scapuint)
 
        // instantiate growslice(typ *type, []any, int) []any
-       fn := syslook("growslice")
-       fn = substArgTypes(fn, elemtype, elemtype)
+       fn := typecheck.LookupRuntime("growslice")
+       fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
 
        // s = growslice(T, s, n)
        nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
                ir.CurFunc.SetWBPos(n.Pos())
 
                // instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
-               fn := syslook("typedslicecopy")
-               fn = substArgTypes(fn, l1.Type().Elem(), l2.Type().Elem())
+               fn := typecheck.LookupRuntime("typedslicecopy")
+               fn = typecheck.SubstArgTypes(fn, l1.Type().Elem(), l2.Type().Elem())
                ptr1, len1 := backingArrayPtrLen(cheapexpr(slice, &nodes))
                ptr2, len2 := backingArrayPtrLen(l2)
                ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
                ptr1, len1 := backingArrayPtrLen(cheapexpr(slice, &nodes))
                ptr2, len2 := backingArrayPtrLen(l2)
 
-               fn := syslook("slicecopy")
-               fn = substArgTypes(fn, ptr1.Type().Elem(), ptr2.Type().Elem())
+               fn := typecheck.LookupRuntime("slicecopy")
+               fn = typecheck.SubstArgTypes(fn, ptr1.Type().Elem(), ptr2.Type().Elem())
                ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(elemtype.Width))
        } else {
                // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
                ix := ir.NewIndexExpr(base.Pos, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1))
                ix.SetBounded(true)
-               addr := nodAddr(ix)
+               addr := typecheck.NodAddr(ix)
 
                sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, l2)
 
-               nwid := cheapexpr(conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, l2), types.Types[types.TUINTPTR]), &nodes)
+               nwid := cheapexpr(typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, l2), types.Types[types.TUINTPTR]), &nodes)
                nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(elemtype.Width))
 
                // instantiate func memmove(to *any, frm *any, length uintptr)
-               fn := syslook("memmove")
-               fn = substArgTypes(fn, elemtype, elemtype)
+               fn := typecheck.LookupRuntime("memmove")
+               fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
                ncopy = mkcall1(fn, nil, &nodes, addr, sptr, nwid)
        }
        ln := append(nodes, ncopy)
 
-       typecheckslice(ln, ctxStmt)
+       typecheck.Stmts(ln)
        walkstmtlist(ln)
        init.Append(ln...)
        return s
        // isAppendOfMake made sure all possible positive values of l2 fit into an uint.
        // The case of l2 overflow when converting from e.g. uint to int is handled by an explicit
        // check of l2 < 0 at runtime which is generated below.
-       l2 := conv(n.Args[1].(*ir.MakeExpr).Len, types.Types[types.TINT])
-       l2 = typecheck(l2, ctxExpr)
+       l2 := typecheck.Conv(n.Args[1].(*ir.MakeExpr).Len, types.Types[types.TINT])
+       l2 = typecheck.Expr(l2)
        n.Args[1] = l2 // walkAppendArgs expects l2 in n.List.Second().
 
        walkAppendArgs(n, init)
        nodes = append(nodes, nifneg)
 
        // s := l1
-       s := temp(l1.Type())
+       s := typecheck.Temp(l1.Type())
        nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, l1))
 
        elemtype := s.Type().Elem()
 
        // n := len(s) + l2
-       nn := temp(types.Types[types.TINT])
+       nn := typecheck.Temp(types.Types[types.TINT])
        nodes = append(nodes, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
 
        // if uint(n) > uint(cap(s))
-       nuint := conv(nn, types.Types[types.TUINT])
-       capuint := conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
+       nuint := typecheck.Conv(nn, types.Types[types.TUINT])
+       capuint := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
        nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, nuint, capuint), nil, nil)
 
        // instantiate growslice(typ *type, old []any, newcap int) []any
-       fn := syslook("growslice")
-       fn = substArgTypes(fn, elemtype, elemtype)
+       fn := typecheck.LookupRuntime("growslice")
+       fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
 
        // s = growslice(T, s, n)
        nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
        nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, nt))
 
        // lptr := &l1[0]
-       l1ptr := temp(l1.Type().Elem().PtrTo())
+       l1ptr := typecheck.Temp(l1.Type().Elem().PtrTo())
        tmp := ir.NewUnaryExpr(base.Pos, ir.OSPTR, l1)
        nodes = append(nodes, ir.NewAssignStmt(base.Pos, l1ptr, tmp))
 
        // sptr := &s[0]
-       sptr := temp(elemtype.PtrTo())
+       sptr := typecheck.Temp(elemtype.PtrTo())
        tmp = ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
        nodes = append(nodes, ir.NewAssignStmt(base.Pos, sptr, tmp))
 
        // hp := &s[len(l1)]
        ix := ir.NewIndexExpr(base.Pos, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1))
        ix.SetBounded(true)
-       hp := convnop(nodAddr(ix), types.Types[types.TUNSAFEPTR])
+       hp := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
 
        // hn := l2 * sizeof(elem(s))
-       hn := conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(elemtype.Width)), types.Types[types.TUINTPTR])
+       hn := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(elemtype.Width)), types.Types[types.TUINTPTR])
 
        clrname := "memclrNoHeapPointers"
        hasPointers := elemtype.HasPointers()
                nodes = append(nodes, clr...)
        }
 
-       typecheckslice(nodes, ctxStmt)
+       typecheck.Stmts(nodes)
        walkstmtlist(nodes)
        init.Append(nodes...)
        return s
        for i, n := range ls {
                n = cheapexpr(n, init)
                if !types.Identical(n.Type(), nsrc.Type().Elem()) {
-                       n = assignconv(n, nsrc.Type().Elem(), "append")
+                       n = typecheck.AssignConv(n, nsrc.Type().Elem(), "append")
                        n = walkexpr(n, init)
                }
                ls[i] = n
 
        var l []ir.Node
 
-       ns := temp(nsrc.Type())
+       ns := typecheck.Temp(nsrc.Type())
        l = append(l, ir.NewAssignStmt(base.Pos, ns, nsrc)) // s = src
 
        na := ir.NewInt(int64(argc))                 // const argc
        nif := ir.NewIfStmt(base.Pos, nil, nil, nil) // if cap(s) - len(s) < argc
        nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OCAP, ns), ir.NewUnaryExpr(base.Pos, ir.OLEN, ns)), na)
 
-       fn := syslook("growslice") //   growslice(<type>, old []T, mincap int) (ret []T)
-       fn = substArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
+       fn := typecheck.LookupRuntime("growslice") //   growslice(<type>, old []T, mincap int) (ret []T)
+       fn = typecheck.SubstArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
 
        nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), typename(ns.Type().Elem()), ns,
                ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns), na)))}
 
        l = append(l, nif)
 
-       nn := temp(types.Types[types.TINT])
+       nn := typecheck.Temp(types.Types[types.TINT])
        l = append(l, ir.NewAssignStmt(base.Pos, nn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns))) // n = len(s)
 
        slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns) // ...s[:n+argc]
                }
        }
 
-       typecheckslice(l, ctxStmt)
+       typecheck.Stmts(l)
        walkstmtlist(l)
        init.Append(l...)
        return ns
                n.Y = cheapexpr(n.Y, init)
                ptrR, lenR := backingArrayPtrLen(n.Y)
 
-               fn := syslook("slicecopy")
-               fn = substArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
+               fn := typecheck.LookupRuntime("slicecopy")
+               fn = typecheck.SubstArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
 
                return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(n.X.Type().Elem().Width))
        }
 
        n.X = walkexpr(n.X, init)
        n.Y = walkexpr(n.Y, init)
-       nl := temp(n.X.Type())
-       nr := temp(n.Y.Type())
+       nl := typecheck.Temp(n.X.Type())
+       nr := typecheck.Temp(n.Y.Type())
        var l []ir.Node
        l = append(l, ir.NewAssignStmt(base.Pos, nl, n.X))
        l = append(l, ir.NewAssignStmt(base.Pos, nr, n.Y))
        nfrm := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nr)
        nto := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nl)
 
-       nlen := temp(types.Types[types.TINT])
+       nlen := typecheck.Temp(types.Types[types.TINT])
 
        // n = len(to)
        l = append(l, ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nl)))
        ne.Likely = true
        l = append(l, ne)
 
-       fn := syslook("memmove")
-       fn = substArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
-       nwid := ir.Node(temp(types.Types[types.TUINTPTR]))
-       setwid := ir.NewAssignStmt(base.Pos, nwid, conv(nlen, types.Types[types.TUINTPTR]))
+       fn := typecheck.LookupRuntime("memmove")
+       fn = typecheck.SubstArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
+       nwid := ir.Node(typecheck.Temp(types.Types[types.TUINTPTR]))
+       setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
        ne.Body.Append(setwid)
        nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(nl.Type().Elem().Width))
        call := mkcall1(fn, nil, init, nto, nfrm, nwid)
        ne.Body.Append(call)
 
-       typecheckslice(l, ctxStmt)
+       typecheck.Stmts(l)
        walkstmtlist(l)
        init.Append(l...)
        return nlen
        // is handled by walkcompare.
        switch a, _ := types.AlgType(t); a {
        case types.AMEM:
-               n := syslook("memequal")
-               n = substArgTypes(n, t, t)
+               n := typecheck.LookupRuntime("memequal")
+               n = typecheck.SubstArgTypes(n, t, t)
                return n, true
        case types.ASPECIAL:
                sym := typesymprefix(".eq", t)
-               n := NewName(sym)
+               n := typecheck.NewName(sym)
                ir.MarkFunc(n)
-               n.SetType(functype(nil, []*ir.Field{
+               n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
                        ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
                        ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
                }, []*ir.Field{
                        tab.SetTypecheck(1)
                        eqtype = ir.NewBinaryExpr(base.Pos, eq, tab, rtyp)
                } else {
-                       nonnil := ir.NewBinaryExpr(base.Pos, brcom(eq), nodnil(), tab)
+                       nonnil := ir.NewBinaryExpr(base.Pos, brcom(eq), typecheck.NodNil(), tab)
                        match := ir.NewBinaryExpr(base.Pos, eq, itabType(tab), rtyp)
                        eqtype = ir.NewLogicalExpr(base.Pos, andor, nonnil, match)
                }
 
                fn, needsize := eqfor(t)
                call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
-               call.Args.Append(nodAddr(cmpl))
-               call.Args.Append(nodAddr(cmpr))
+               call.Args.Append(typecheck.NodAddr(cmpl))
+               call.Args.Append(typecheck.NodAddr(cmpr))
                if needsize {
                        call.Args.Append(ir.NewInt(t.Width))
                }
                        } else {
                                elemType := t.Elem().ToUnsigned()
                                cmplw := ir.Node(ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i)))
-                               cmplw = conv(cmplw, elemType) // convert to unsigned
-                               cmplw = conv(cmplw, convType) // widen
+                               cmplw = typecheck.Conv(cmplw, elemType) // convert to unsigned
+                               cmplw = typecheck.Conv(cmplw, convType) // widen
                                cmprw := ir.Node(ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i)))
-                               cmprw = conv(cmprw, elemType)
-                               cmprw = conv(cmprw, convType)
+                               cmprw = typecheck.Conv(cmprw, elemType)
+                               cmprw = typecheck.Conv(cmprw, convType)
                                // For code like this:  uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
                                // ssa will generate a single large load.
                                for offset := int64(1); offset < step; offset++ {
                                        lb := ir.Node(ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i+offset)))
-                                       lb = conv(lb, elemType)
-                                       lb = conv(lb, convType)
+                                       lb = typecheck.Conv(lb, elemType)
+                                       lb = typecheck.Conv(lb, convType)
                                        lb = ir.NewBinaryExpr(base.Pos, ir.OLSH, lb, ir.NewInt(8*t.Elem().Width*offset))
                                        cmplw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmplw, lb)
                                        rb := ir.Node(ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i+offset)))
-                                       rb = conv(rb, elemType)
-                                       rb = conv(rb, convType)
+                                       rb = typecheck.Conv(rb, elemType)
+                                       rb = typecheck.Conv(rb, convType)
                                        rb = ir.NewBinaryExpr(base.Pos, ir.OLSH, rb, ir.NewInt(8*t.Elem().Width*offset))
                                        cmprw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmprw, rb)
                                }
                expr = ir.NewBool(n.Op() == ir.OEQ)
                // We still need to use cmpl and cmpr, in case they contain
                // an expression which might panic. See issue 23837.
-               t := temp(cmpl.Type())
-               a1 := typecheck(ir.NewAssignStmt(base.Pos, t, cmpl), ctxStmt)
-               a2 := typecheck(ir.NewAssignStmt(base.Pos, t, cmpr), ctxStmt)
+               t := typecheck.Temp(cmpl.Type())
+               a1 := typecheck.Stmt(ir.NewAssignStmt(base.Pos, t, cmpl))
+               a2 := typecheck.Stmt(ir.NewAssignStmt(base.Pos, t, cmpr))
                init.Append(a1, a2)
        }
        return finishcompare(n, expr, init)
                n = copyexpr(n, n.Type(), init)
        }
 
-       return conv(n, t)
+       return typecheck.Conv(n, t)
 }
 
 func walkcompareInterface(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                                        convType = types.Types[types.TUINT16]
                                        step = 2
                                }
-                               ncsubstr := conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i))), convType)
+                               ncsubstr := typecheck.Conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i))), convType)
                                csubstr := int64(s[i])
                                // Calculate large constant from bytes as sequence of shifts and ors.
                                // Like this:  uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
                                // ssa will combine this into a single large load.
                                for offset := 1; offset < step; offset++ {
-                                       b := conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i+offset))), convType)
+                                       b := typecheck.Conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i+offset))), convType)
                                        b = ir.NewBinaryExpr(base.Pos, ir.OLSH, b, ir.NewInt(int64(8*offset)))
                                        ncsubstr = ir.NewBinaryExpr(base.Pos, ir.OOR, ncsubstr, b)
                                        csubstr |= int64(s[i+offset]) << uint8(8*offset)
                }
        } else {
                // sys_cmpstring(s1, s2) :: 0
-               r = mkcall("cmpstring", types.Types[types.TINT], init, conv(n.X, types.Types[types.TSTRING]), conv(n.Y, types.Types[types.TSTRING]))
+               r = mkcall("cmpstring", types.Types[types.TINT], init, typecheck.Conv(n.X, types.Types[types.TSTRING]), typecheck.Conv(n.Y, types.Types[types.TSTRING]))
                r = ir.NewBinaryExpr(base.Pos, n.Op(), r, ir.NewInt(0))
        }
 
 // The result of finishcompare MUST be assigned back to n, e.g.
 //     n.Left = finishcompare(n.Left, x, r, init)
 func finishcompare(n *ir.BinaryExpr, r ir.Node, init *ir.Nodes) ir.Node {
-       r = typecheck(r, ctxExpr)
-       r = conv(r, n.Type())
+       r = typecheck.Expr(r)
+       r = typecheck.Conv(r, n.Type())
        r = walkexpr(r, init)
        return r
 }
        origArgs := make([]ir.Node, len(n.Args))
        var funcArgs []*ir.Field
        for i, arg := range n.Args {
-               s := lookupN("a", i)
+               s := typecheck.LookupNum("a", i)
                if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
                        origArgs[i] = arg
                        arg = arg.(*ir.ConvExpr).X
        t := ir.NewFuncType(base.Pos, nil, funcArgs, nil)
 
        wrapCall_prgen++
-       sym := lookupN("wrap·", wrapCall_prgen)
-       fn := dclfunc(sym, t)
+       sym := typecheck.LookupNum("wrap·", wrapCall_prgen)
+       fn := typecheck.DeclFunc(sym, t)
 
        args := ir.ParamNames(t.Type())
        for i, origArg := range origArgs {
        }
        fn.Body = []ir.Node{call}
 
-       funcbody()
+       typecheck.FinishFuncBody()
 
-       typecheckFunc(fn)
-       typecheckslice(fn.Body, ctxStmt)
-       Target.Decls = append(Target.Decls, fn)
+       typecheck.Func(fn)
+       typecheck.Stmts(fn.Body)
+       typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
 
        call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.Args)
-       return walkexpr(typecheck(call, ctxStmt), init)
-}
-
-// substArgTypes substitutes the given list of types for
-// successive occurrences of the "any" placeholder in the
-// type syntax expression n.Type.
-// The result of substArgTypes MUST be assigned back to old, e.g.
-//     n.Left = substArgTypes(n.Left, t1, t2)
-func substArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
-       n := old.CloneName()
-
-       for _, t := range types_ {
-               types.CalcSize(t)
-       }
-       n.SetType(types.SubstAny(n.Type(), &types_))
-       if len(types_) > 0 {
-               base.Fatalf("substArgTypes: too many argument types")
-       }
-       return n
+       return walkexpr(typecheck.Stmt(call), init)
 }
 
 // canMergeLoads reports whether the backend optimization passes for
        }
 
        n.X = cheapexpr(n.X, init)
-       init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.X, types.Types[types.TUNSAFEPTR]), typename(elem), conv(count, types.Types[types.TUINTPTR])))
+       init.Append(mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), typename(elem), typecheck.Conv(count, types.Types[types.TUINTPTR])))
        return n
 }
 
                        n := n.(*ir.ConvExpr)
                        if n.X.Type().IsUnsafePtr() {
                                n.X = cheapexpr(n.X, init)
-                               originals = append(originals, convnop(n.X, types.Types[types.TUNSAFEPTR]))
+                               originals = append(originals, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]))
                        }
                }
        }
 
        cheap := cheapexpr(n, init)
 
-       slice := mkdotargslice(types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
+       slice := typecheck.MakeDotArgs(types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
        slice.SetEsc(ir.EscNone)
 
-       init.Append(mkcall("checkptrArithmetic", nil, init, convnop(cheap, types.Types[types.TUNSAFEPTR]), slice))
+       init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice))
        // TODO(khr): Mark backing store of slice as dead. This will allow us to reuse
        // the backing store for multiple calls to checkptrArithmetic.
 
 // appendWalkStmt typechecks and walks stmt and then appends it to init.
 func appendWalkStmt(init *ir.Nodes, stmt ir.Node) {
        op := stmt.Op()
-       n := typecheck(stmt, ctxStmt)
+       n := typecheck.Stmt(stmt)
        if op == ir.OAS || op == ir.OAS2 {
                // If the assignment has side effects, walkexpr will append them
                // directly to init for us, while walkstmt will wrap it in an OBLOCK.
 
--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import "cmd/compile/internal/types"
+
+// ----------------------------------------------------------------------------
+// Export format
+
+// Tags. Must be < 0.
+const (
+       // Objects
+       packageTag = -(iota + 1)
+       constTag
+       typeTag
+       varTag
+       funcTag
+       endTag
+
+       // Types
+       namedTag
+       arrayTag
+       sliceTag
+       dddTag
+       structTag
+       pointerTag
+       signatureTag
+       interfaceTag
+       mapTag
+       chanTag
+
+       // Values
+       falseTag
+       trueTag
+       int64Tag
+       floatTag
+       fractionTag // not used by gc
+       complexTag
+       stringTag
+       nilTag
+       unknownTag // not used by gc (only appears in packages with errors)
+
+       // Type aliases
+       aliasTag
+)
+
+var predecl []*types.Type // initialized lazily
+
+func predeclared() []*types.Type {
+       if predecl == nil {
+               // initialize lazily to be sure that all
+               // elements have been initialized before
+               predecl = []*types.Type{
+                       // basic types
+                       types.Types[types.TBOOL],
+                       types.Types[types.TINT],
+                       types.Types[types.TINT8],
+                       types.Types[types.TINT16],
+                       types.Types[types.TINT32],
+                       types.Types[types.TINT64],
+                       types.Types[types.TUINT],
+                       types.Types[types.TUINT8],
+                       types.Types[types.TUINT16],
+                       types.Types[types.TUINT32],
+                       types.Types[types.TUINT64],
+                       types.Types[types.TUINTPTR],
+                       types.Types[types.TFLOAT32],
+                       types.Types[types.TFLOAT64],
+                       types.Types[types.TCOMPLEX64],
+                       types.Types[types.TCOMPLEX128],
+                       types.Types[types.TSTRING],
+
+                       // basic type aliases
+                       types.ByteType,
+                       types.RuneType,
+
+                       // error
+                       types.ErrorType,
+
+                       // untyped types
+                       types.UntypedBool,
+                       types.UntypedInt,
+                       types.UntypedRune,
+                       types.UntypedFloat,
+                       types.UntypedComplex,
+                       types.UntypedString,
+                       types.Types[types.TNIL],
+
+                       // package unsafe
+                       types.Types[types.TUNSAFEPTR],
+
+                       // invalid type (package contains errors)
+                       types.Types[types.Txxx],
+
+                       // any type, for builtin export data
+                       types.Types[types.TANY],
+               }
+       }
+       return predecl
+}
 
--- /dev/null
+// Code generated by mkbuiltin.go. DO NOT EDIT.
+
+package typecheck
+
+import (
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+)
+
+var runtimeDecls = [...]struct {
+       name string
+       tag  int
+       typ  int
+}{
+       {"newobject", funcTag, 4},
+       {"mallocgc", funcTag, 8},
+       {"panicdivide", funcTag, 9},
+       {"panicshift", funcTag, 9},
+       {"panicmakeslicelen", funcTag, 9},
+       {"panicmakeslicecap", funcTag, 9},
+       {"throwinit", funcTag, 9},
+       {"panicwrap", funcTag, 9},
+       {"gopanic", funcTag, 11},
+       {"gorecover", funcTag, 14},
+       {"goschedguarded", funcTag, 9},
+       {"goPanicIndex", funcTag, 16},
+       {"goPanicIndexU", funcTag, 18},
+       {"goPanicSliceAlen", funcTag, 16},
+       {"goPanicSliceAlenU", funcTag, 18},
+       {"goPanicSliceAcap", funcTag, 16},
+       {"goPanicSliceAcapU", funcTag, 18},
+       {"goPanicSliceB", funcTag, 16},
+       {"goPanicSliceBU", funcTag, 18},
+       {"goPanicSlice3Alen", funcTag, 16},
+       {"goPanicSlice3AlenU", funcTag, 18},
+       {"goPanicSlice3Acap", funcTag, 16},
+       {"goPanicSlice3AcapU", funcTag, 18},
+       {"goPanicSlice3B", funcTag, 16},
+       {"goPanicSlice3BU", funcTag, 18},
+       {"goPanicSlice3C", funcTag, 16},
+       {"goPanicSlice3CU", funcTag, 18},
+       {"printbool", funcTag, 19},
+       {"printfloat", funcTag, 21},
+       {"printint", funcTag, 23},
+       {"printhex", funcTag, 25},
+       {"printuint", funcTag, 25},
+       {"printcomplex", funcTag, 27},
+       {"printstring", funcTag, 29},
+       {"printpointer", funcTag, 30},
+       {"printuintptr", funcTag, 31},
+       {"printiface", funcTag, 30},
+       {"printeface", funcTag, 30},
+       {"printslice", funcTag, 30},
+       {"printnl", funcTag, 9},
+       {"printsp", funcTag, 9},
+       {"printlock", funcTag, 9},
+       {"printunlock", funcTag, 9},
+       {"concatstring2", funcTag, 34},
+       {"concatstring3", funcTag, 35},
+       {"concatstring4", funcTag, 36},
+       {"concatstring5", funcTag, 37},
+       {"concatstrings", funcTag, 39},
+       {"cmpstring", funcTag, 40},
+       {"intstring", funcTag, 43},
+       {"slicebytetostring", funcTag, 44},
+       {"slicebytetostringtmp", funcTag, 45},
+       {"slicerunetostring", funcTag, 48},
+       {"stringtoslicebyte", funcTag, 50},
+       {"stringtoslicerune", funcTag, 53},
+       {"slicecopy", funcTag, 54},
+       {"decoderune", funcTag, 55},
+       {"countrunes", funcTag, 56},
+       {"convI2I", funcTag, 57},
+       {"convT16", funcTag, 58},
+       {"convT32", funcTag, 58},
+       {"convT64", funcTag, 58},
+       {"convTstring", funcTag, 58},
+       {"convTslice", funcTag, 58},
+       {"convT2E", funcTag, 59},
+       {"convT2Enoptr", funcTag, 59},
+       {"convT2I", funcTag, 59},
+       {"convT2Inoptr", funcTag, 59},
+       {"assertE2I", funcTag, 57},
+       {"assertE2I2", funcTag, 60},
+       {"assertI2I", funcTag, 57},
+       {"assertI2I2", funcTag, 60},
+       {"panicdottypeE", funcTag, 61},
+       {"panicdottypeI", funcTag, 61},
+       {"panicnildottype", funcTag, 62},
+       {"ifaceeq", funcTag, 64},
+       {"efaceeq", funcTag, 64},
+       {"fastrand", funcTag, 66},
+       {"makemap64", funcTag, 68},
+       {"makemap", funcTag, 69},
+       {"makemap_small", funcTag, 70},
+       {"mapaccess1", funcTag, 71},
+       {"mapaccess1_fast32", funcTag, 72},
+       {"mapaccess1_fast64", funcTag, 72},
+       {"mapaccess1_faststr", funcTag, 72},
+       {"mapaccess1_fat", funcTag, 73},
+       {"mapaccess2", funcTag, 74},
+       {"mapaccess2_fast32", funcTag, 75},
+       {"mapaccess2_fast64", funcTag, 75},
+       {"mapaccess2_faststr", funcTag, 75},
+       {"mapaccess2_fat", funcTag, 76},
+       {"mapassign", funcTag, 71},
+       {"mapassign_fast32", funcTag, 72},
+       {"mapassign_fast32ptr", funcTag, 72},
+       {"mapassign_fast64", funcTag, 72},
+       {"mapassign_fast64ptr", funcTag, 72},
+       {"mapassign_faststr", funcTag, 72},
+       {"mapiterinit", funcTag, 77},
+       {"mapdelete", funcTag, 77},
+       {"mapdelete_fast32", funcTag, 78},
+       {"mapdelete_fast64", funcTag, 78},
+       {"mapdelete_faststr", funcTag, 78},
+       {"mapiternext", funcTag, 79},
+       {"mapclear", funcTag, 80},
+       {"makechan64", funcTag, 82},
+       {"makechan", funcTag, 83},
+       {"chanrecv1", funcTag, 85},
+       {"chanrecv2", funcTag, 86},
+       {"chansend1", funcTag, 88},
+       {"closechan", funcTag, 30},
+       {"writeBarrier", varTag, 90},
+       {"typedmemmove", funcTag, 91},
+       {"typedmemclr", funcTag, 92},
+       {"typedslicecopy", funcTag, 93},
+       {"selectnbsend", funcTag, 94},
+       {"selectnbrecv", funcTag, 95},
+       {"selectnbrecv2", funcTag, 97},
+       {"selectsetpc", funcTag, 98},
+       {"selectgo", funcTag, 99},
+       {"block", funcTag, 9},
+       {"makeslice", funcTag, 100},
+       {"makeslice64", funcTag, 101},
+       {"makeslicecopy", funcTag, 102},
+       {"growslice", funcTag, 104},
+       {"memmove", funcTag, 105},
+       {"memclrNoHeapPointers", funcTag, 106},
+       {"memclrHasPointers", funcTag, 106},
+       {"memequal", funcTag, 107},
+       {"memequal0", funcTag, 108},
+       {"memequal8", funcTag, 108},
+       {"memequal16", funcTag, 108},
+       {"memequal32", funcTag, 108},
+       {"memequal64", funcTag, 108},
+       {"memequal128", funcTag, 108},
+       {"f32equal", funcTag, 109},
+       {"f64equal", funcTag, 109},
+       {"c64equal", funcTag, 109},
+       {"c128equal", funcTag, 109},
+       {"strequal", funcTag, 109},
+       {"interequal", funcTag, 109},
+       {"nilinterequal", funcTag, 109},
+       {"memhash", funcTag, 110},
+       {"memhash0", funcTag, 111},
+       {"memhash8", funcTag, 111},
+       {"memhash16", funcTag, 111},
+       {"memhash32", funcTag, 111},
+       {"memhash64", funcTag, 111},
+       {"memhash128", funcTag, 111},
+       {"f32hash", funcTag, 111},
+       {"f64hash", funcTag, 111},
+       {"c64hash", funcTag, 111},
+       {"c128hash", funcTag, 111},
+       {"strhash", funcTag, 111},
+       {"interhash", funcTag, 111},
+       {"nilinterhash", funcTag, 111},
+       {"int64div", funcTag, 112},
+       {"uint64div", funcTag, 113},
+       {"int64mod", funcTag, 112},
+       {"uint64mod", funcTag, 113},
+       {"float64toint64", funcTag, 114},
+       {"float64touint64", funcTag, 115},
+       {"float64touint32", funcTag, 116},
+       {"int64tofloat64", funcTag, 117},
+       {"uint64tofloat64", funcTag, 118},
+       {"uint32tofloat64", funcTag, 119},
+       {"complex128div", funcTag, 120},
+       {"racefuncenter", funcTag, 31},
+       {"racefuncenterfp", funcTag, 9},
+       {"racefuncexit", funcTag, 9},
+       {"raceread", funcTag, 31},
+       {"racewrite", funcTag, 31},
+       {"racereadrange", funcTag, 121},
+       {"racewriterange", funcTag, 121},
+       {"msanread", funcTag, 121},
+       {"msanwrite", funcTag, 121},
+       {"msanmove", funcTag, 122},
+       {"checkptrAlignment", funcTag, 123},
+       {"checkptrArithmetic", funcTag, 125},
+       {"libfuzzerTraceCmp1", funcTag, 127},
+       {"libfuzzerTraceCmp2", funcTag, 129},
+       {"libfuzzerTraceCmp4", funcTag, 130},
+       {"libfuzzerTraceCmp8", funcTag, 131},
+       {"libfuzzerTraceConstCmp1", funcTag, 127},
+       {"libfuzzerTraceConstCmp2", funcTag, 129},
+       {"libfuzzerTraceConstCmp4", funcTag, 130},
+       {"libfuzzerTraceConstCmp8", funcTag, 131},
+       {"x86HasPOPCNT", varTag, 6},
+       {"x86HasSSE41", varTag, 6},
+       {"x86HasFMA", varTag, 6},
+       {"armHasVFPv4", varTag, 6},
+       {"arm64HasATOMICS", varTag, 6},
+}
+
+func runtimeTypes() []*types.Type {
+       var typs [132]*types.Type
+       typs[0] = types.ByteType
+       typs[1] = types.NewPtr(typs[0])
+       typs[2] = types.Types[types.TANY]
+       typs[3] = types.NewPtr(typs[2])
+       typs[4] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+       typs[5] = types.Types[types.TUINTPTR]
+       typs[6] = types.Types[types.TBOOL]
+       typs[7] = types.Types[types.TUNSAFEPTR]
+       typs[8] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+       typs[9] = NewFuncType(nil, nil, nil)
+       typs[10] = types.Types[types.TINTER]
+       typs[11] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])}, nil)
+       typs[12] = types.Types[types.TINT32]
+       typs[13] = types.NewPtr(typs[12])
+       typs[14] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[13])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])})
+       typs[15] = types.Types[types.TINT]
+       typs[16] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
+       typs[17] = types.Types[types.TUINT]
+       typs[18] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[17]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
+       typs[19] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}, nil)
+       typs[20] = types.Types[types.TFLOAT64]
+       typs[21] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, nil)
+       typs[22] = types.Types[types.TINT64]
+       typs[23] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, nil)
+       typs[24] = types.Types[types.TUINT64]
+       typs[25] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
+       typs[26] = types.Types[types.TCOMPLEX128]
+       typs[27] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])}, nil)
+       typs[28] = types.Types[types.TSTRING]
+       typs[29] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, nil)
+       typs[30] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
+       typs[31] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+       typs[32] = types.NewArray(typs[0], 32)
+       typs[33] = types.NewPtr(typs[32])
+       typs[34] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[35] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[36] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[37] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[38] = types.NewSlice(typs[28])
+       typs[39] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[38])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[40] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+       typs[41] = types.NewArray(typs[0], 4)
+       typs[42] = types.NewPtr(typs[41])
+       typs[43] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[42]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[44] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[45] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[46] = types.RuneType
+       typs[47] = types.NewSlice(typs[46])
+       typs[48] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[47])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+       typs[49] = types.NewSlice(typs[0])
+       typs[50] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[49])})
+       typs[51] = types.NewArray(typs[46], 32)
+       typs[52] = types.NewPtr(typs[51])
+       typs[53] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[52]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[47])})
+       typs[54] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+       typs[55] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[46]), ir.NewField(base.Pos, nil, nil, typs[15])})
+       typs[56] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+       typs[57] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
+       typs[58] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+       typs[59] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
+       typs[60] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2]), ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[61] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
+       typs[62] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
+       typs[63] = types.NewPtr(typs[5])
+       typs[64] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[65] = types.Types[types.TUINT32]
+       typs[66] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
+       typs[67] = types.NewMap(typs[2], typs[2])
+       typs[68] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
+       typs[69] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
+       typs[70] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
+       typs[71] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+       typs[72] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+       typs[73] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+       typs[74] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[75] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[76] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[77] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+       typs[78] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
+       typs[79] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+       typs[80] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67])}, nil)
+       typs[81] = types.NewChan(typs[2], types.Cboth)
+       typs[82] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
+       typs[83] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
+       typs[84] = types.NewChan(typs[2], types.Crecv)
+       typs[85] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+       typs[86] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[87] = types.NewChan(typs[2], types.Csend)
+       typs[88] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+       typs[89] = types.NewArray(typs[0], 3)
+       typs[90] = NewStructType([]*ir.Field{ir.NewField(base.Pos, Lookup("enabled"), nil, typs[6]), ir.NewField(base.Pos, Lookup("pad"), nil, typs[89]), ir.NewField(base.Pos, Lookup("needed"), nil, typs[6]), ir.NewField(base.Pos, Lookup("cgo"), nil, typs[6]), ir.NewField(base.Pos, Lookup("alignme"), nil, typs[24])})
+       typs[91] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+       typs[92] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+       typs[93] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+       typs[94] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[95] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[96] = types.NewPtr(typs[6])
+       typs[97] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[96]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[98] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63])}, nil)
+       typs[99] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[100] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+       typs[101] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+       typs[102] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+       typs[103] = types.NewSlice(typs[2])
+       typs[104] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[103]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[103])})
+       typs[105] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+       typs[106] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+       typs[107] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[108] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[109] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+       typs[110] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
+       typs[111] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
+       typs[112] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
+       typs[113] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
+       typs[114] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
+       typs[115] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
+       typs[116] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
+       typs[117] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
+       typs[118] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
+       typs[119] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
+       typs[120] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26]), ir.NewField(base.Pos, nil, nil, typs[26])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])})
+       typs[121] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+       typs[122] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+       typs[123] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+       typs[124] = types.NewSlice(typs[7])
+       typs[125] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[124])}, nil)
+       typs[126] = types.Types[types.TUINT8]
+       typs[127] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[126]), ir.NewField(base.Pos, nil, nil, typs[126])}, nil)
+       typs[128] = types.Types[types.TUINT16]
+       typs[129] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[128]), ir.NewField(base.Pos, nil, nil, typs[128])}, nil)
+       typs[130] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65]), ir.NewField(base.Pos, nil, nil, typs[65])}, nil)
+       typs[131] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
+       return typs[:]
+}
 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc_test
+package typecheck
 
 import (
        "bytes"
 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package typecheck
 
 import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-       "cmd/internal/src"
        "fmt"
        "go/constant"
        "go/token"
        "math/big"
        "strings"
        "unicode"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/src"
 )
 
 func roundFloat(v constant.Value, sz int64) constant.Value {
 
 // TODO(mdempsky): Replace these with better APIs.
 func convlit(n ir.Node, t *types.Type) ir.Node    { return convlit1(n, t, false, nil) }
-func defaultlit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) }
+func DefaultLit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) }
 
 // convlit1 converts an untyped expression n to type t. If n already
 // has a type, convlit1 has no effect.
        case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.OREAL, ir.OIMAG:
                ot := operandType(n.Op(), t)
                if ot == nil {
-                       n = defaultlit(n, nil)
+                       n = DefaultLit(n, nil)
                        break
                }
 
        case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT, ir.OOROR, ir.OANDAND, ir.OCOMPLEX:
                ot := operandType(n.Op(), t)
                if ot == nil {
-                       n = defaultlit(n, nil)
+                       n = DefaultLit(n, nil)
                        break
                }
 
        ir.ORSH: token.SHR,
 }
 
-// evalConst returns a constant-evaluated expression equivalent to n.
-// If n is not a constant, evalConst returns n.
-// Otherwise, evalConst returns a new OLITERAL with the same value as n,
+// EvalConst returns a constant-evaluated expression equivalent to n.
+// If n is not a constant, EvalConst returns n.
+// Otherwise, EvalConst returns a new OLITERAL with the same value as n,
 // and with .Orig pointing back to n.
-func evalConst(n ir.Node) ir.Node {
+func EvalConst(n ir.Node) ir.Node {
        // Pick off just the opcodes that can be constant evaluated.
        switch n.Op() {
        case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
                        if n.Type().IsUnsigned() {
                                prec = uint(n.Type().Size() * 8)
                        }
-                       return origConst(n, constant.UnaryOp(tokenForOp[n.Op()], nl.Val(), prec))
+                       return OrigConst(n, constant.UnaryOp(tokenForOp[n.Op()], nl.Val(), prec))
                }
 
        case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
                        if n.Op() == ir.ODIV && n.Type().IsInteger() {
                                tok = token.QUO_ASSIGN // integer division
                        }
-                       return origConst(n, constant.BinaryOp(nl.Val(), tok, rval))
+                       return OrigConst(n, constant.BinaryOp(nl.Val(), tok, rval))
                }
 
        case ir.OOROR, ir.OANDAND:
                n := n.(*ir.LogicalExpr)
                nl, nr := n.X, n.Y
                if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
-                       return origConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val()))
+                       return OrigConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val()))
                }
 
        case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
                n := n.(*ir.BinaryExpr)
                nl, nr := n.X, n.Y
                if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
-                       return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
+                       return OrigBool(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
                }
 
        case ir.OLSH, ir.ORSH:
                                n.SetType(nil)
                                break
                        }
-                       return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
+                       return OrigConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
                }
 
        case ir.OCONV, ir.ORUNESTR:
                n := n.(*ir.ConvExpr)
                nl := n.X
                if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
-                       return origConst(n, convertVal(nl.Val(), n.Type(), true))
+                       return OrigConst(n, convertVal(nl.Val(), n.Type(), true))
                }
 
        case ir.OCONVNOP:
                if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
                        // set so n.Orig gets OCONV instead of OCONVNOP
                        n.SetOp(ir.OCONV)
-                       return origConst(n, nl.Val())
+                       return OrigConst(n, nl.Val())
                }
 
        case ir.OADDSTR:
                        for _, c := range s {
                                strs = append(strs, ir.StringVal(c))
                        }
-                       return origConst(n, constant.MakeString(strings.Join(strs, "")))
+                       return OrigConst(n, constant.MakeString(strings.Join(strs, "")))
                }
                newList := make([]ir.Node, 0, need)
                for i := 0; i < len(s); i++ {
 
                                nl := ir.Copy(n).(*ir.AddStringExpr)
                                nl.List.Set(s[i:i2])
-                               newList = append(newList, origConst(nl, constant.MakeString(strings.Join(strs, ""))))
+                               newList = append(newList, OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
                                i = i2 - 1
                        } else {
                                newList = append(newList, s[i])
                switch nl.Type().Kind() {
                case types.TSTRING:
                        if ir.IsConst(nl, constant.String) {
-                               return origIntConst(n, int64(len(ir.StringVal(nl))))
+                               return OrigInt(n, int64(len(ir.StringVal(nl))))
                        }
                case types.TARRAY:
                        if !anyCallOrChan(nl) {
-                               return origIntConst(n, nl.Type().NumElem())
+                               return OrigInt(n, nl.Type().NumElem())
                        }
                }
 
        case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
                n := n.(*ir.UnaryExpr)
-               return origIntConst(n, evalunsafe(n))
+               return OrigInt(n, evalunsafe(n))
 
        case ir.OREAL:
                n := n.(*ir.UnaryExpr)
                nl := n.X
                if nl.Op() == ir.OLITERAL {
-                       return origConst(n, constant.Real(nl.Val()))
+                       return OrigConst(n, constant.Real(nl.Val()))
                }
 
        case ir.OIMAG:
                n := n.(*ir.UnaryExpr)
                nl := n.X
                if nl.Op() == ir.OLITERAL {
-                       return origConst(n, constant.Imag(nl.Val()))
+                       return OrigConst(n, constant.Imag(nl.Val()))
                }
 
        case ir.OCOMPLEX:
                n := n.(*ir.BinaryExpr)
                nl, nr := n.X, n.Y
                if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
-                       return origConst(n, makeComplex(nl.Val(), nr.Val()))
+                       return OrigConst(n, makeComplex(nl.Val(), nr.Val()))
                }
        }
 
        ir.OBITNOT: "bitwise complement",
 }
 
-// origConst returns an OLITERAL with orig n and value v.
-func origConst(n ir.Node, v constant.Value) ir.Node {
+// OrigConst returns an OLITERAL with orig n and value v.
+func OrigConst(n ir.Node, v constant.Value) ir.Node {
        lno := ir.SetPos(n)
        v = convertVal(v, n.Type(), false)
        base.Pos = lno
        return ir.NewConstExpr(v, n)
 }
 
-func origBoolConst(n ir.Node, v bool) ir.Node {
-       return origConst(n, constant.MakeBool(v))
+func OrigBool(n ir.Node, v bool) ir.Node {
+       return OrigConst(n, constant.MakeBool(v))
 }
 
-func origIntConst(n ir.Node, v int64) ir.Node {
-       return origConst(n, constant.MakeInt64(v))
+func OrigInt(n ir.Node, v int64) ir.Node {
+       return OrigConst(n, constant.MakeInt64(v))
 }
 
 // defaultlit on both nodes simultaneously;
        return nil
 }
 
-// indexconst checks if Node n contains a constant expression
+// IndexConst checks if Node n contains a constant expression
 // representable as a non-negative int and returns its value.
 // If n is not a constant expression, not representable as an
 // integer, or negative, it returns -1. If n is too large, it
 // returns -2.
-func indexconst(n ir.Node) int64 {
+func IndexConst(n ir.Node) int64 {
        if n.Op() != ir.OLITERAL {
                return -1
        }
        }
        return show
 }
+
+// evalunsafe evaluates a package unsafe operation and returns the result.
+func evalunsafe(n ir.Node) int64 {
+       switch n.Op() {
+       case ir.OALIGNOF, ir.OSIZEOF:
+               n := n.(*ir.UnaryExpr)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
+               tr := n.X.Type()
+               if tr == nil {
+                       return 0
+               }
+               types.CalcSize(tr)
+               if n.Op() == ir.OALIGNOF {
+                       return int64(tr.Align)
+               }
+               return tr.Width
+
+       case ir.OOFFSETOF:
+               // must be a selector.
+               n := n.(*ir.UnaryExpr)
+               if n.X.Op() != ir.OXDOT {
+                       base.Errorf("invalid expression %v", n)
+                       return 0
+               }
+               sel := n.X.(*ir.SelectorExpr)
+
+               // Remember base of selector to find it back after dot insertion.
+               // Since r->left may be mutated by typechecking, check it explicitly
+               // first to track it correctly.
+               sel.X = Expr(sel.X)
+               sbase := sel.X
+
+               tsel := Expr(sel)
+               n.X = tsel
+               if tsel.Type() == nil {
+                       return 0
+               }
+               switch tsel.Op() {
+               case ir.ODOT, ir.ODOTPTR:
+                       break
+               case ir.OCALLPART:
+                       base.Errorf("invalid expression %v: argument is a method value", n)
+                       return 0
+               default:
+                       base.Errorf("invalid expression %v", n)
+                       return 0
+               }
+
+               // Sum offsets for dots until we reach sbase.
+               var v int64
+               var next ir.Node
+               for r := tsel; r != sbase; r = next {
+                       switch r.Op() {
+                       case ir.ODOTPTR:
+                               // For Offsetof(s.f), s may itself be a pointer,
+                               // but accessing f must not otherwise involve
+                               // indirection via embedded pointer types.
+                               r := r.(*ir.SelectorExpr)
+                               if r.X != sbase {
+                                       base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.X)
+                                       return 0
+                               }
+                               fallthrough
+                       case ir.ODOT:
+                               r := r.(*ir.SelectorExpr)
+                               v += r.Offset
+                               next = r.X
+                       default:
+                               ir.Dump("unsafenmagic", tsel)
+                               base.Fatalf("impossible %v node after dot insertion", r.Op())
+                       }
+               }
+               return v
+       }
+
+       base.Fatalf("unexpected op %v", n.Op())
+       return 0
+}
 
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+       "fmt"
+       "strconv"
+       "strings"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/src"
+)
+
+var DeclContext ir.Class // PEXTERN/PAUTO
+
+func AssignDefn(left []ir.Node, defn ir.Node) {
+       for _, n := range left {
+               if n.Sym() != nil {
+                       n.Sym().SetUniq(true)
+               }
+       }
+
+       var nnew, nerr int
+       for i, n := range left {
+               if ir.IsBlank(n) {
+                       continue
+               }
+               if !assignableName(n) {
+                       base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n)
+                       nerr++
+                       continue
+               }
+
+               if !n.Sym().Uniq() {
+                       base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym())
+                       n.SetDiag(true)
+                       nerr++
+                       continue
+               }
+
+               n.Sym().SetUniq(false)
+               if n.Sym().Block == types.Block {
+                       continue
+               }
+
+               nnew++
+               n := NewName(n.Sym())
+               Declare(n, DeclContext)
+               n.Defn = defn
+               defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
+               left[i] = n
+       }
+
+       if nnew == 0 && nerr == 0 {
+               base.ErrorfAt(defn.Pos(), "no new variables on left side of :=")
+       }
+}
+
+// := declarations
+func assignableName(n ir.Node) bool {
+       switch n.Op() {
+       case ir.ONAME,
+               ir.ONONAME,
+               ir.OPACK,
+               ir.OTYPE,
+               ir.OLITERAL:
+               return n.Sym() != nil
+       }
+
+       return false
+}
+
+func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
+       if tfn.Op() != ir.OTFUNC {
+               base.Fatalf("expected OTFUNC node, got %v", tfn)
+       }
+
+       fn := ir.NewFunc(base.Pos)
+       fn.Nname = ir.NewFuncNameAt(base.Pos, sym, fn)
+       fn.Nname.Defn = fn
+       fn.Nname.Ntype = tfn
+       ir.MarkFunc(fn.Nname)
+       StartFuncBody(fn)
+       fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
+       return fn
+}
+
+// declare variables from grammar
+// new_name_list (type | [type] = expr_list)
+func DeclVars(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
+       var init []ir.Node
+       doexpr := len(el) > 0
+
+       if len(el) == 1 && len(vl) > 1 {
+               e := el[0]
+               as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
+               as2.Rhs = []ir.Node{e}
+               for _, v := range vl {
+                       as2.Lhs.Append(v)
+                       Declare(v, DeclContext)
+                       v.Ntype = t
+                       v.Defn = as2
+                       if ir.CurFunc != nil {
+                               init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
+                       }
+               }
+
+               return append(init, as2)
+       }
+
+       for i, v := range vl {
+               var e ir.Node
+               if doexpr {
+                       if i >= len(el) {
+                               base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
+                               break
+                       }
+                       e = el[i]
+               }
+
+               Declare(v, DeclContext)
+               v.Ntype = t
+
+               if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
+                       if ir.CurFunc != nil {
+                               init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
+                       }
+                       as := ir.NewAssignStmt(base.Pos, v, e)
+                       init = append(init, as)
+                       if e != nil {
+                               v.Defn = as
+                       }
+               }
+       }
+
+       if len(el) > len(vl) {
+               base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
+       }
+       return init
+}
+
+// Declare records that Node n declares symbol n.Sym in the specified
+// declaration context.
+func Declare(n *ir.Name, ctxt ir.Class) {
+       if ir.IsBlank(n) {
+               return
+       }
+
+       s := n.Sym()
+
+       // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+       if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg {
+               base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
+       }
+
+       gen := 0
+       if ctxt == ir.PEXTERN {
+               if s.Name == "init" {
+                       base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
+               }
+               if s.Name == "main" && s.Pkg.Name == "main" {
+                       base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
+               }
+               Target.Externs = append(Target.Externs, n)
+       } else {
+               if ir.CurFunc == nil && ctxt == ir.PAUTO {
+                       base.Pos = n.Pos()
+                       base.Fatalf("automatic outside function")
+               }
+               if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
+                       ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
+               }
+               if n.Op() == ir.OTYPE {
+                       declare_typegen++
+                       gen = declare_typegen
+               } else if n.Op() == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") {
+                       vargen++
+                       gen = vargen
+               }
+               types.Pushdcl(s)
+               n.Curfn = ir.CurFunc
+       }
+
+       if ctxt == ir.PAUTO {
+               n.SetFrameOffset(0)
+       }
+
+       if s.Block == types.Block {
+               // functype will print errors about duplicate function arguments.
+               // Don't repeat the error here.
+               if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
+                       Redeclared(n.Pos(), s, "in this block")
+               }
+       }
+
+       s.Block = types.Block
+       s.Lastlineno = base.Pos
+       s.Def = n
+       n.Vargen = int32(gen)
+       n.Class_ = ctxt
+       if ctxt == ir.PFUNC {
+               n.Sym().SetFunc(true)
+       }
+
+       autoexport(n, ctxt)
+}
+
+// Export marks n for export (or reexport).
+func Export(n *ir.Name) {
+       if n.Sym().OnExportList() {
+               return
+       }
+       n.Sym().SetOnExportList(true)
+
+       if base.Flag.E != 0 {
+               fmt.Printf("export symbol %v\n", n.Sym())
+       }
+
+       Target.Exports = append(Target.Exports, n)
+}
+
+// Redeclared emits a diagnostic about symbol s being redeclared at pos.
+func Redeclared(pos src.XPos, s *types.Sym, where string) {
+       if !s.Lastlineno.IsKnown() {
+               pkgName := DotImportRefs[s.Def.(*ir.Ident)]
+               base.ErrorfAt(pos, "%v redeclared %s\n"+
+                       "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
+       } else {
+               prevPos := s.Lastlineno
+
+               // When an import and a declaration collide in separate files,
+               // present the import as the "redeclared", because the declaration
+               // is visible where the import is, but not vice versa.
+               // See issue 4510.
+               if s.Def == nil {
+                       pos, prevPos = prevPos, pos
+               }
+
+               base.ErrorfAt(pos, "%v redeclared %s\n"+
+                       "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
+       }
+}
+
+// declare the function proper
+// and declare the arguments.
+// called in extern-declaration context
+// returns in auto-declaration context.
+func StartFuncBody(fn *ir.Func) {
+       // change the declaration context from extern to auto
+       funcStack = append(funcStack, funcStackEnt{ir.CurFunc, DeclContext})
+       ir.CurFunc = fn
+       DeclContext = ir.PAUTO
+
+       types.Markdcl()
+
+       if fn.Nname.Ntype != nil {
+               funcargs(fn.Nname.Ntype.(*ir.FuncType))
+       } else {
+               funcargs2(fn.Type())
+       }
+}
+
+// finish the body.
+// called in auto-declaration context.
+// returns in extern-declaration context.
+func FinishFuncBody() {
+       // change the declaration context from auto to previous context
+       types.Popdcl()
+       var e funcStackEnt
+       funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
+       ir.CurFunc, DeclContext = e.curfn, e.dclcontext
+}
+
+func CheckFuncStack() {
+       if len(funcStack) != 0 {
+               base.Fatalf("funcStack is non-empty: %v", len(funcStack))
+       }
+}
+
+// turn a parsed function declaration into a type
+func NewFuncType(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
+       funarg := func(n *ir.Field) *types.Field {
+               lno := base.Pos
+               base.Pos = n.Pos
+
+               if n.Ntype != nil {
+                       n.Type = typecheckNtype(n.Ntype).Type()
+                       n.Ntype = nil
+               }
+
+               f := types.NewField(n.Pos, n.Sym, n.Type)
+               f.SetIsDDD(n.IsDDD)
+               if n.Decl != nil {
+                       n.Decl.SetType(f.Type)
+                       f.Nname = n.Decl
+               }
+
+               base.Pos = lno
+               return f
+       }
+       funargs := func(nn []*ir.Field) []*types.Field {
+               res := make([]*types.Field, len(nn))
+               for i, n := range nn {
+                       res[i] = funarg(n)
+               }
+               return res
+       }
+
+       var recv *types.Field
+       if nrecv != nil {
+               recv = funarg(nrecv)
+       }
+
+       t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults))
+       checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
+       return t
+}
+
+// convert a parsed id/type list into
+// a type for struct/interface/arglist
+func NewStructType(l []*ir.Field) *types.Type {
+       lno := base.Pos
+
+       fields := make([]*types.Field, len(l))
+       for i, n := range l {
+               base.Pos = n.Pos
+
+               if n.Ntype != nil {
+                       n.Type = typecheckNtype(n.Ntype).Type()
+                       n.Ntype = nil
+               }
+               f := types.NewField(n.Pos, n.Sym, n.Type)
+               if n.Embedded {
+                       checkembeddedtype(n.Type)
+                       f.Embedded = 1
+               }
+               f.Note = n.Note
+               fields[i] = f
+       }
+       checkdupfields("field", fields)
+
+       base.Pos = lno
+       return types.NewStruct(types.LocalPkg, fields)
+}
+
+// Add a method, declared as a function.
+// - msym is the method symbol
+// - t is function type (with receiver)
+// Returns a pointer to the existing or added Field; or nil if there's an error.
+func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
+       if msym == nil {
+               base.Fatalf("no method symbol")
+       }
+
+       // get parent type sym
+       rf := t.Recv() // ptr to this structure
+       if rf == nil {
+               base.Errorf("missing receiver")
+               return nil
+       }
+
+       mt := types.ReceiverBaseType(rf.Type)
+       if mt == nil || mt.Sym() == nil {
+               pa := rf.Type
+               t := pa
+               if t != nil && t.IsPtr() {
+                       if t.Sym() != nil {
+                               base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
+                               return nil
+                       }
+                       t = t.Elem()
+               }
+
+               switch {
+               case t == nil || t.Broke():
+                       // rely on typecheck having complained before
+               case t.Sym() == nil:
+                       base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
+               case t.IsPtr():
+                       base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
+               case t.IsInterface():
+                       base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
+               default:
+                       // Should have picked off all the reasons above,
+                       // but just in case, fall back to generic error.
+                       base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
+               }
+               return nil
+       }
+
+       if local && mt.Sym().Pkg != types.LocalPkg {
+               base.Errorf("cannot define new methods on non-local type %v", mt)
+               return nil
+       }
+
+       if msym.IsBlank() {
+               return nil
+       }
+
+       if mt.IsStruct() {
+               for _, f := range mt.Fields().Slice() {
+                       if f.Sym == msym {
+                               base.Errorf("type %v has both field and method named %v", mt, msym)
+                               f.SetBroke(true)
+                               return nil
+                       }
+               }
+       }
+
+       for _, f := range mt.Methods().Slice() {
+               if msym.Name != f.Sym.Name {
+                       continue
+               }
+               // types.Identical only checks that incoming and result parameters match,
+               // so explicitly check that the receiver parameters match too.
+               if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
+                       base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
+               }
+               return f
+       }
+
+       f := types.NewField(base.Pos, msym, t)
+       f.Nname = n.Nname
+       f.SetNointerface(nointerface)
+
+       mt.Methods().Append(f)
+       return f
+}
+
+func autoexport(n *ir.Name, ctxt ir.Class) {
+       if n.Sym().Pkg != types.LocalPkg {
+               return
+       }
+       if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || DeclContext != ir.PEXTERN {
+               return
+       }
+       if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
+               return
+       }
+
+       if types.IsExported(n.Sym().Name) || initname(n.Sym().Name) {
+               Export(n)
+       }
+       if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
+               n.Sym().SetAsm(true)
+               Target.Asms = append(Target.Asms, n)
+       }
+}
+
+// checkdupfields emits errors for duplicately named fields or methods in
+// a list of struct or interface types.
+func checkdupfields(what string, fss ...[]*types.Field) {
+       seen := make(map[*types.Sym]bool)
+       for _, fs := range fss {
+               for _, f := range fs {
+                       if f.Sym == nil || f.Sym.IsBlank() {
+                               continue
+                       }
+                       if seen[f.Sym] {
+                               base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
+                               continue
+                       }
+                       seen[f.Sym] = true
+               }
+       }
+}
+
+// structs, functions, and methods.
+// they don't belong here, but where do they belong?
+func checkembeddedtype(t *types.Type) {
+       if t == nil {
+               return
+       }
+
+       if t.Sym() == nil && t.IsPtr() {
+               t = t.Elem()
+               if t.IsInterface() {
+                       base.Errorf("embedded type cannot be a pointer to interface")
+               }
+       }
+
+       if t.IsPtr() || t.IsUnsafePtr() {
+               base.Errorf("embedded type cannot be a pointer")
+       } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
+               t.ForwardType().Embedlineno = base.Pos
+       }
+}
+
+// declare individual names - var, typ, const
+
+var declare_typegen int
+
+func fakeRecvField() *types.Field {
+       return types.NewField(src.NoXPos, nil, types.FakeRecvType())
+}
+
+var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
+
+type funcStackEnt struct {
+       curfn      *ir.Func
+       dclcontext ir.Class
+}
+
+func funcarg(n *ir.Field, ctxt ir.Class) {
+       if n.Sym == nil {
+               return
+       }
+
+       name := ir.NewNameAt(n.Pos, n.Sym)
+       n.Decl = name
+       name.Ntype = n.Ntype
+       name.SetIsDDD(n.IsDDD)
+       Declare(name, ctxt)
+
+       vargen++
+       n.Decl.Vargen = int32(vargen)
+}
+
+func funcarg2(f *types.Field, ctxt ir.Class) {
+       if f.Sym == nil {
+               return
+       }
+       n := ir.NewNameAt(f.Pos, f.Sym)
+       f.Nname = n
+       n.SetType(f.Type)
+       n.SetIsDDD(f.IsDDD())
+       Declare(n, ctxt)
+}
+
+func funcargs(nt *ir.FuncType) {
+       if nt.Op() != ir.OTFUNC {
+               base.Fatalf("funcargs %v", nt.Op())
+       }
+
+       // re-start the variable generation number
+       // we want to use small numbers for the return variables,
+       // so let them have the chunk starting at 1.
+       //
+       // TODO(mdempsky): This is ugly, and only necessary because
+       // esc.go uses Vargen to figure out result parameters' index
+       // within the result tuple.
+       vargen = len(nt.Results)
+
+       // declare the receiver and in arguments.
+       if nt.Recv != nil {
+               funcarg(nt.Recv, ir.PPARAM)
+       }
+       for _, n := range nt.Params {
+               funcarg(n, ir.PPARAM)
+       }
+
+       oldvargen := vargen
+       vargen = 0
+
+       // declare the out arguments.
+       gen := len(nt.Params)
+       for _, n := range nt.Results {
+               if n.Sym == nil {
+                       // Name so that escape analysis can track it. ~r stands for 'result'.
+                       n.Sym = LookupNum("~r", gen)
+                       gen++
+               }
+               if n.Sym.IsBlank() {
+                       // Give it a name so we can assign to it during return. ~b stands for 'blank'.
+                       // The name must be different from ~r above because if you have
+                       //      func f() (_ int)
+                       //      func g() int
+                       // f is allowed to use a plain 'return' with no arguments, while g is not.
+                       // So the two cases must be distinguished.
+                       n.Sym = LookupNum("~b", gen)
+                       gen++
+               }
+
+               funcarg(n, ir.PPARAMOUT)
+       }
+
+       vargen = oldvargen
+}
+
+// Same as funcargs, except run over an already constructed TFUNC.
+// This happens during import, where the hidden_fndcl rule has
+// used functype directly to parse the function's type.
+func funcargs2(t *types.Type) {
+       if t.Kind() != types.TFUNC {
+               base.Fatalf("funcargs2 %v", t)
+       }
+
+       for _, f := range t.Recvs().Fields().Slice() {
+               funcarg2(f, ir.PPARAM)
+       }
+       for _, f := range t.Params().Fields().Slice() {
+               funcarg2(f, ir.PPARAM)
+       }
+       for _, f := range t.Results().Fields().Slice() {
+               funcarg2(f, ir.PPARAMOUT)
+       }
+}
+
+func initname(s string) bool {
+       return s == "init"
+}
+
+func tointerface(nmethods []*ir.Field) *types.Type {
+       if len(nmethods) == 0 {
+               return types.Types[types.TINTER]
+       }
+
+       lno := base.Pos
+
+       methods := make([]*types.Field, len(nmethods))
+       for i, n := range nmethods {
+               base.Pos = n.Pos
+               if n.Ntype != nil {
+                       n.Type = typecheckNtype(n.Ntype).Type()
+                       n.Ntype = nil
+               }
+               methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
+       }
+
+       base.Pos = lno
+       return types.NewInterface(types.LocalPkg, methods)
+}
+
+var vargen int
+
+func Temp(t *types.Type) *ir.Name {
+       return TempAt(base.Pos, ir.CurFunc, t)
+}
+
+// make a new Node off the books
+func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
+       if curfn == nil {
+               base.Fatalf("no curfn for tempAt")
+       }
+       if curfn.Op() == ir.OCLOSURE {
+               ir.Dump("tempAt", curfn)
+               base.Fatalf("adding tempAt to wrong closure function")
+       }
+       if t == nil {
+               base.Fatalf("tempAt called with nil type")
+       }
+
+       s := &types.Sym{
+               Name: autotmpname(len(curfn.Dcl)),
+               Pkg:  types.LocalPkg,
+       }
+       n := ir.NewNameAt(pos, s)
+       s.Def = n
+       n.SetType(t)
+       n.Class_ = ir.PAUTO
+       n.SetEsc(ir.EscNever)
+       n.Curfn = curfn
+       n.SetUsed(true)
+       n.SetAutoTemp(true)
+       curfn.Dcl = append(curfn.Dcl, n)
+
+       types.CalcSize(t)
+
+       return n
+}
+
+// autotmpname returns the name for an autotmp variable numbered n.
+func autotmpname(n int) string {
+       // Give each tmp a different name so that they can be registerized.
+       // Add a preceding . to avoid clashing with legal names.
+       const prefix = ".autotmp_"
+       // Start with a buffer big enough to hold a large n.
+       b := []byte(prefix + "      ")[:len(prefix)]
+       b = strconv.AppendInt(b, int64(n), 10)
+       return types.InternString(b)
+}
+
+// f is method type, with receiver.
+// return function type, receiver as first argument (or not).
+func NewMethodType(f *types.Type, receiver *types.Type) *types.Type {
+       inLen := f.Params().Fields().Len()
+       if receiver != nil {
+               inLen++
+       }
+       in := make([]*ir.Field, 0, inLen)
+
+       if receiver != nil {
+               d := ir.NewField(base.Pos, nil, nil, receiver)
+               in = append(in, d)
+       }
+
+       for _, t := range f.Params().Fields().Slice() {
+               d := ir.NewField(base.Pos, nil, nil, t.Type)
+               d.IsDDD = t.IsDDD()
+               in = append(in, d)
+       }
+
+       outLen := f.Results().Fields().Len()
+       out := make([]*ir.Field, 0, outLen)
+       for _, t := range f.Results().Fields().Slice() {
+               d := ir.NewField(base.Pos, nil, nil, t.Type)
+               out = append(out, d)
+       }
+
+       return NewFuncType(nil, in, out)
+}
 
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+       "go/constant"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/src"
+)
+
+// importalias declares symbol s as an imported type alias with type t.
+// ipkg is the package being imported
+func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
+       return importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t)
+}
+
+// importconst declares symbol s as an imported constant with type t and value val.
+// ipkg is the package being imported
+func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name {
+       n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t)
+       n.SetVal(val)
+       return n
+}
+
+// importfunc declares symbol s as an imported function with type t.
+// ipkg is the package being imported
+func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
+       n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
+
+       fn := ir.NewFunc(pos)
+       fn.SetType(t)
+       n.SetFunc(fn)
+       fn.Nname = n
+
+       return n
+}
+
+// importobj declares symbol s as an imported object representable by op.
+// ipkg is the package being imported
+func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name {
+       n := importsym(ipkg, pos, s, op, ctxt)
+       n.SetType(t)
+       if ctxt == ir.PFUNC {
+               n.Sym().SetFunc(true)
+       }
+       return n
+}
+
+func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name {
+       if n := s.PkgDef(); n != nil {
+               base.Fatalf("importsym of symbol that already exists: %v", n)
+       }
+
+       n := ir.NewDeclNameAt(pos, op, s)
+       n.Class_ = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too?
+       s.SetPkgDef(n)
+       s.Importdef = ipkg
+       return n
+}
+
+// importtype returns the named type declared by symbol s.
+// If no such type has been declared yet, a forward declaration is returned.
+// ipkg is the package being imported
+func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *ir.Name {
+       n := importsym(ipkg, pos, s, ir.OTYPE, ir.PEXTERN)
+       n.SetType(types.NewNamed(n))
+       return n
+}
+
+// importvar declares symbol s as an imported variable with type t.
+// ipkg is the package being imported
+func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
+       return importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t)
+}
 
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+
+       "fmt"
+)
+
+// package all the arguments that match a ... T parameter into a []T.
+func MakeDotArgs(typ *types.Type, args []ir.Node) ir.Node {
+       var n ir.Node
+       if len(args) == 0 {
+               n = NodNil()
+               n.SetType(typ)
+       } else {
+               lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
+               lit.List.Append(args...)
+               lit.SetImplicit(true)
+               n = lit
+       }
+
+       n = Expr(n)
+       if n.Type() == nil {
+               base.Fatalf("mkdotargslice: typecheck failed")
+       }
+       return n
+}
+
+// FixVariadicCall rewrites calls to variadic functions to use an
+// explicit ... argument if one is not already present.
+func FixVariadicCall(call *ir.CallExpr) {
+       fntype := call.X.Type()
+       if !fntype.IsVariadic() || call.IsDDD {
+               return
+       }
+
+       vi := fntype.NumParams() - 1
+       vt := fntype.Params().Field(vi).Type
+
+       args := call.Args
+       extra := args[vi:]
+       slice := MakeDotArgs(vt, extra)
+       for i := range extra {
+               extra[i] = nil // allow GC
+       }
+
+       call.Args.Set(append(args[:vi], slice))
+       call.IsDDD = true
+}
+
+// ClosureType returns the struct type used to hold all the information
+// needed in the closure for clo (clo must be a OCLOSURE node).
+// The address of a variable of the returned type can be cast to a func.
+func ClosureType(clo *ir.ClosureExpr) *types.Type {
+       // Create closure in the form of a composite literal.
+       // supposing the closure captures an int i and a string s
+       // and has one float64 argument and no results,
+       // the generated code looks like:
+       //
+       //      clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
+       //
+       // The use of the struct provides type information to the garbage
+       // collector so that it can walk the closure. We could use (in this case)
+       // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
+       // The information appears in the binary in the form of type descriptors;
+       // the struct is unnamed so that closures in multiple packages with the
+       // same struct type can share the descriptor.
+       fields := []*ir.Field{
+               ir.NewField(base.Pos, Lookup(".F"), nil, types.Types[types.TUINTPTR]),
+       }
+       for _, v := range clo.Func.ClosureVars {
+               typ := v.Type()
+               if !v.Byval() {
+                       typ = types.NewPtr(typ)
+               }
+               fields = append(fields, ir.NewField(base.Pos, v.Sym(), nil, typ))
+       }
+       typ := NewStructType(fields)
+       typ.SetNoalg(true)
+       return typ
+}
+
+// PartialCallType returns the struct type used to hold all the information
+// needed in the closure for n (n must be a OCALLPART node).
+// The address of a variable of the returned type can be cast to a func.
+func PartialCallType(n *ir.CallPartExpr) *types.Type {
+       t := NewStructType([]*ir.Field{
+               ir.NewField(base.Pos, Lookup("F"), nil, types.Types[types.TUINTPTR]),
+               ir.NewField(base.Pos, Lookup("R"), nil, n.X.Type()),
+       })
+       t.SetNoalg(true)
+       return t
+}
+
+// CaptureVars is called in a separate phase after all typechecking is done.
+// It decides whether each variable captured by a closure should be captured
+// by value or by reference.
+// We use value capturing for values <= 128 bytes that are never reassigned
+// after capturing (effectively constant).
+func CaptureVars(fn *ir.Func) {
+       lno := base.Pos
+       base.Pos = fn.Pos()
+       cvars := fn.ClosureVars
+       out := cvars[:0]
+       for _, v := range cvars {
+               if v.Type() == nil {
+                       // If v.Type is nil, it means v looked like it
+                       // was going to be used in the closure, but
+                       // isn't. This happens in struct literals like
+                       // s{f: x} where we can't distinguish whether
+                       // f is a field identifier or expression until
+                       // resolving s.
+                       continue
+               }
+               out = append(out, v)
+
+               // type check the & of closed variables outside the closure,
+               // so that the outer frame also grabs them and knows they escape.
+               types.CalcSize(v.Type())
+
+               var outer ir.Node
+               outer = v.Outer
+               outermost := v.Defn.(*ir.Name)
+
+               // out parameters will be assigned to implicitly upon return.
+               if outermost.Class_ != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
+                       v.SetByval(true)
+               } else {
+                       outermost.Name().SetAddrtaken(true)
+                       outer = NodAddr(outer)
+               }
+
+               if base.Flag.LowerM > 1 {
+                       var name *types.Sym
+                       if v.Curfn != nil && v.Curfn.Nname != nil {
+                               name = v.Curfn.Sym()
+                       }
+                       how := "ref"
+                       if v.Byval() {
+                               how = "value"
+                       }
+                       base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width))
+               }
+
+               outer = Expr(outer)
+               fn.ClosureEnter.Append(outer)
+       }
+
+       fn.ClosureVars = out
+       base.Pos = lno
+}
+
+// typecheckclosure typechecks an OCLOSURE node. It also creates the named
+// function associated with the closure.
+// TODO: This creation of the named function should probably really be done in a
+// separate pass from type-checking.
+func typecheckclosure(clo *ir.ClosureExpr, top int) {
+       fn := clo.Func
+       // Set current associated iota value, so iota can be used inside
+       // function in ConstSpec, see issue #22344
+       if x := getIotaValue(); x >= 0 {
+               fn.Iota = x
+       }
+
+       fn.ClosureType = check(fn.ClosureType, ctxType)
+       clo.SetType(fn.ClosureType.Type())
+       fn.SetClosureCalled(top&ctxCallee != 0)
+
+       // Do not typecheck fn twice, otherwise, we will end up pushing
+       // fn to Target.Decls multiple times, causing initLSym called twice.
+       // See #30709
+       if fn.Typecheck() == 1 {
+               return
+       }
+
+       for _, ln := range fn.ClosureVars {
+               n := ln.Defn
+               if !n.Name().Captured() {
+                       n.Name().SetCaptured(true)
+                       if n.Name().Decldepth == 0 {
+                               base.Fatalf("typecheckclosure: var %v does not have decldepth assigned", n)
+                       }
+
+                       // Ignore assignments to the variable in straightline code
+                       // preceding the first capturing by a closure.
+                       if n.Name().Decldepth == decldepth {
+                               n.Name().SetAssigned(false)
+                       }
+               }
+       }
+
+       fn.Nname.SetSym(closurename(ir.CurFunc))
+       ir.MarkFunc(fn.Nname)
+       Func(fn)
+
+       // Type check the body now, but only if we're inside a function.
+       // At top level (in a variable initialization: curfn==nil) we're not
+       // ready to type check code yet; we'll check it later, because the
+       // underlying closure function we create is added to Target.Decls.
+       if ir.CurFunc != nil && clo.Type() != nil {
+               oldfn := ir.CurFunc
+               ir.CurFunc = fn
+               olddd := decldepth
+               decldepth = 1
+               Stmts(fn.Body)
+               decldepth = olddd
+               ir.CurFunc = oldfn
+       }
+
+       Target.Decls = append(Target.Decls, fn)
+}
+
+// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
+// because they're a copy of an already checked body.
+func ImportedBody(fn *ir.Func) {
+       lno := ir.SetPos(fn.Nname)
+
+       ImportBody(fn)
+
+       // typecheckinl is only for imported functions;
+       // their bodies may refer to unsafe as long as the package
+       // was marked safe during import (which was checked then).
+       // the ->inl of a local function has been typechecked before caninl copied it.
+       pkg := fnpkg(fn.Nname)
+
+       if pkg == types.LocalPkg || pkg == nil {
+               return // typecheckinl on local function
+       }
+
+       if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
+               fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
+       }
+
+       savefn := ir.CurFunc
+       ir.CurFunc = fn
+       Stmts(fn.Inl.Body)
+       ir.CurFunc = savefn
+
+       // During expandInline (which imports fn.Func.Inl.Body),
+       // declarations are added to fn.Func.Dcl by funcHdr(). Move them
+       // to fn.Func.Inl.Dcl for consistency with how local functions
+       // behave. (Append because typecheckinl may be called multiple
+       // times.)
+       fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...)
+       fn.Dcl = nil
+
+       base.Pos = lno
+}
+
+// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
+// the ->sym can be re-used in the local package, so peel it off the receiver's type.
+func fnpkg(fn *ir.Name) *types.Pkg {
+       if ir.IsMethod(fn) {
+               // method
+               rcvr := fn.Type().Recv().Type
+
+               if rcvr.IsPtr() {
+                       rcvr = rcvr.Elem()
+               }
+               if rcvr.Sym() == nil {
+                       base.Fatalf("receiver with no sym: [%v] %L  (%v)", fn.Sym(), fn, rcvr)
+               }
+               return rcvr.Sym().Pkg
+       }
+
+       // non-method
+       return fn.Sym().Pkg
+}
+
+// CaptureVarsComplete is set to true when the capturevars phase is done.
+var CaptureVarsComplete bool
+
+// closurename generates a new unique name for a closure within
+// outerfunc.
+func closurename(outerfunc *ir.Func) *types.Sym {
+       outer := "glob."
+       prefix := "func"
+       gen := &globClosgen
+
+       if outerfunc != nil {
+               if outerfunc.OClosure != nil {
+                       prefix = ""
+               }
+
+               outer = ir.FuncName(outerfunc)
+
+               // There may be multiple functions named "_". In those
+               // cases, we can't use their individual Closgens as it
+               // would lead to name clashes.
+               if !ir.IsBlank(outerfunc.Nname) {
+                       gen = &outerfunc.Closgen
+               }
+       }
+
+       *gen++
+       return Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
+}
+
+// globClosgen is like Func.Closgen, but for the global scope.
+var globClosgen int32
+
+// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
+// for partial calls.
+func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func {
+       rcvrtype := dot.X.Type()
+       sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
+
+       if sym.Uniq() {
+               return sym.Def.(*ir.Func)
+       }
+       sym.SetUniq(true)
+
+       savecurfn := ir.CurFunc
+       saveLineNo := base.Pos
+       ir.CurFunc = nil
+
+       // Set line number equal to the line number where the method is declared.
+       var m *types.Field
+       if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
+               base.Pos = m.Pos
+       }
+       // Note: !m.Pos.IsKnown() happens for method expressions where
+       // the method is implicitly declared. The Error method of the
+       // built-in error type is one such method.  We leave the line
+       // number at the use of the method expression in this
+       // case. See issue 29389.
+
+       tfn := ir.NewFuncType(base.Pos, nil,
+               NewFuncParams(t0.Params(), true),
+               NewFuncParams(t0.Results(), false))
+
+       fn := DeclFunc(sym, tfn)
+       fn.SetDupok(true)
+       fn.SetNeedctxt(true)
+
+       // Declare and initialize variable holding receiver.
+       cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
+       ptr := NewName(Lookup(".this"))
+       Declare(ptr, ir.PAUTO)
+       ptr.SetUsed(true)
+       var body []ir.Node
+       if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
+               ptr.SetType(rcvrtype)
+               body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr))
+       } else {
+               ptr.SetType(types.NewPtr(rcvrtype))
+               body = append(body, ir.NewAssignStmt(base.Pos, ptr, NodAddr(cr)))
+       }
+
+       call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
+       call.Args.Set(ir.ParamNames(tfn.Type()))
+       call.IsDDD = tfn.Type().IsVariadic()
+       if t0.NumResults() != 0 {
+               ret := ir.NewReturnStmt(base.Pos, nil)
+               ret.Results = []ir.Node{call}
+               body = append(body, ret)
+       } else {
+               body = append(body, call)
+       }
+
+       fn.Body.Set(body)
+       FinishFuncBody()
+
+       Func(fn)
+       // Need to typecheck the body of the just-generated wrapper.
+       // typecheckslice() requires that Curfn is set when processing an ORETURN.
+       ir.CurFunc = fn
+       Stmts(fn.Body)
+       sym.Def = fn
+       Target.Decls = append(Target.Decls, fn)
+       ir.CurFunc = savecurfn
+       base.Pos = saveLineNo
+
+       return fn
+}
+
+func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
+       switch n.Op() {
+       case ir.ODOTINTER, ir.ODOTMETH:
+               break
+
+       default:
+               base.Fatalf("invalid typecheckpartialcall")
+       }
+       dot := n.(*ir.SelectorExpr)
+
+       // Create top-level function.
+       fn := makepartialcall(dot, dot.Type(), sym)
+       fn.SetWrapper(true)
+
+       return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
+}
 
 // they're expected to change much more rapidly, so they're omitted
 // here. See exportWriter's varExt/funcExt/etc methods for details.
 
-package gc
+package typecheck
 
 import (
        "bufio"
        "bytes"
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-       "cmd/internal/goobj"
-       "cmd/internal/src"
        "crypto/md5"
        "encoding/binary"
        "fmt"
        "math/big"
        "sort"
        "strings"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/goobj"
+       "cmd/internal/src"
 )
 
 // Current indexed export format version. Increase with each format change.
        interfaceType
 )
 
-func iexport(out *bufio.Writer) {
+func WriteExports(out *bufio.Writer) {
        p := iexporter{
                allPkgs:     map[*types.Pkg]bool{},
                stringIndex: map[string]uint64{},
        case ir.OLITERAL:
                // Constant.
                // TODO(mdempsky): Do we still need this typecheck? If so, why?
-               n = typecheck(n, ctxExpr).(*ir.Name)
+               n = Expr(n).(*ir.Name)
                w.tag('C')
                w.pos(n.Pos())
                w.value(n.Type(), n.Val())
 
 // Indexed package import.
 // See iexport.go for the export data format.
 
-package gc
+package typecheck
 
 import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-       "cmd/internal/bio"
-       "cmd/internal/goobj"
-       "cmd/internal/obj"
-       "cmd/internal/src"
        "encoding/binary"
        "fmt"
        "go/constant"
        "math/big"
        "os"
        "strings"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/bio"
+       "cmd/internal/goobj"
+       "cmd/internal/obj"
+       "cmd/internal/src"
 )
 
 // An iimporterAndOffset identifies an importer and an offset within
 }
 
 var (
-       // declImporter maps from imported identifiers to an importer
+       // DeclImporter maps from imported identifiers to an importer
        // and offset where that identifier's declaration can be read.
-       declImporter = map[*types.Sym]iimporterAndOffset{}
+       DeclImporter = map[*types.Sym]iimporterAndOffset{}
 
        // inlineImporter is like declImporter, but for inline bodies
        // for function and method symbols.
                return n.(*ir.Name)
        }
 
-       r := importReaderFor(id.Sym(), declImporter)
+       r := importReaderFor(id.Sym(), DeclImporter)
        if r == nil {
                // Can happen if user tries to reference an undeclared name.
                return n
        return r.doDecl(n.Sym())
 }
 
-func expandInline(fn *ir.Func) {
+func ImportBody(fn *ir.Func) {
        if fn.Inl.Body != nil {
                return
        }
        return i
 }
 
-func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) {
+func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) {
        ird := &intReader{in, pkg}
 
        version := ird.uint64()
                        s := pkg.Lookup(p.stringAt(ird.uint64()))
                        off := ird.uint64()
 
-                       if _, ok := declImporter[s]; !ok {
-                               declImporter[s] = iimporterAndOffset{p, off}
+                       if _, ok := DeclImporter[s]; !ok {
+                               DeclImporter[s] = iimporterAndOffset{p, off}
                        }
                }
        }
                base.Fatalf("%v already has inline body", fn)
        }
 
-       funchdr(fn)
+       StartFuncBody(fn)
        body := r.stmtList()
-       funcbody()
+       FinishFuncBody()
        if body == nil {
                //
                // Make sure empty body is not interpreted as
                        // names after import. That's okay: swt.go only needs
                        // Sym for diagnostics anyway.
                        caseVar := ir.NewNameAt(cas.Pos(), r.ident())
-                       declare(caseVar, dclcontext)
+                       Declare(caseVar, DeclContext)
                        cas.Vars = []ir.Node{caseVar}
                        caseVar.Defn = sw.(*ir.SwitchStmt).Tag
                }
                pos := r.pos()
                typ := r.typ()
 
-               n := npos(pos, nodnil())
+               n := npos(pos, NodNil())
                n.SetType(typ)
                return n
 
                return ir.NewUnaryExpr(r.pos(), op, r.expr())
 
        case ir.OADDR:
-               return nodAddrAt(r.pos(), r.expr())
+               return NodAddrAt(r.pos(), r.expr())
 
        case ir.ODEREF:
                return ir.NewStarExpr(r.pos(), r.expr())
                lhs := ir.NewDeclNameAt(pos, ir.ONAME, r.ident())
                lhs.SetType(r.typ())
 
-               declare(lhs, ir.PAUTO)
+               Declare(lhs, ir.PAUTO)
 
                var stmts ir.Nodes
                stmts.Append(ir.NewDecl(base.Pos, ir.ODCL, lhs))
                var sym *types.Sym
                pos := r.pos()
                if label := r.string(); label != "" {
-                       sym = lookup(label)
+                       sym = Lookup(label)
                }
                return ir.NewBranchStmt(pos, op, sym)
 
        case ir.OLABEL:
-               return ir.NewLabelStmt(r.pos(), lookup(r.string()))
+               return ir.NewLabelStmt(r.pos(), Lookup(r.string()))
 
        case ir.OEND:
                return nil
 
 
 // +build darwin dragonfly freebsd linux netbsd openbsd
 
-package gc
+package typecheck
 
 import (
        "os"
 
 
 // +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
 
-package gc
+package typecheck
 
 import (
        "io"
 
        var b bytes.Buffer
        fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
        fmt.Fprintln(&b)
-       fmt.Fprintln(&b, "package gc")
+       fmt.Fprintln(&b, "package typecheck")
        fmt.Fprintln(&b)
        fmt.Fprintln(&b, `import (`)
        fmt.Fprintln(&b, `      "cmd/compile/internal/ir"`)
 
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/src"
+)
+
+// range
+func typecheckrange(n *ir.RangeStmt) {
+       // Typechecking order is important here:
+       // 0. first typecheck range expression (slice/map/chan),
+       //      it is evaluated only once and so logically it is not part of the loop.
+       // 1. typecheck produced values,
+       //      this part can declare new vars and so it must be typechecked before body,
+       //      because body can contain a closure that captures the vars.
+       // 2. decldepth++ to denote loop body.
+       // 3. typecheck body.
+       // 4. decldepth--.
+       typecheckrangeExpr(n)
+
+       // second half of dance, the first half being typecheckrangeExpr
+       n.SetTypecheck(1)
+       ls := n.Vars
+       for i1, n1 := range ls {
+               if n1.Typecheck() == 0 {
+                       ls[i1] = AssignExpr(ls[i1])
+               }
+       }
+
+       decldepth++
+       Stmts(n.Body)
+       decldepth--
+}
+
+func typecheckrangeExpr(n *ir.RangeStmt) {
+       n.X = Expr(n.X)
+
+       t := n.X.Type()
+       if t == nil {
+               return
+       }
+       // delicate little dance.  see typecheckas2
+       ls := n.Vars
+       for i1, n1 := range ls {
+               if !ir.DeclaredBy(n1, n) {
+                       ls[i1] = AssignExpr(ls[i1])
+               }
+       }
+
+       if t.IsPtr() && t.Elem().IsArray() {
+               t = t.Elem()
+       }
+       n.SetType(t)
+
+       var t1, t2 *types.Type
+       toomany := false
+       switch t.Kind() {
+       default:
+               base.ErrorfAt(n.Pos(), "cannot range over %L", n.X)
+               return
+
+       case types.TARRAY, types.TSLICE:
+               t1 = types.Types[types.TINT]
+               t2 = t.Elem()
+
+       case types.TMAP:
+               t1 = t.Key()
+               t2 = t.Elem()
+
+       case types.TCHAN:
+               if !t.ChanDir().CanRecv() {
+                       base.ErrorfAt(n.Pos(), "invalid operation: range %v (receive from send-only type %v)", n.X, n.X.Type())
+                       return
+               }
+
+               t1 = t.Elem()
+               t2 = nil
+               if len(n.Vars) == 2 {
+                       toomany = true
+               }
+
+       case types.TSTRING:
+               t1 = types.Types[types.TINT]
+               t2 = types.RuneType
+       }
+
+       if len(n.Vars) > 2 || toomany {
+               base.ErrorfAt(n.Pos(), "too many variables in range")
+       }
+
+       var v1, v2 ir.Node
+       if len(n.Vars) != 0 {
+               v1 = n.Vars[0]
+       }
+       if len(n.Vars) > 1 {
+               v2 = n.Vars[1]
+       }
+
+       // this is not only an optimization but also a requirement in the spec.
+       // "if the second iteration variable is the blank identifier, the range
+       // clause is equivalent to the same clause with only the first variable
+       // present."
+       if ir.IsBlank(v2) {
+               if v1 != nil {
+                       n.Vars = []ir.Node{v1}
+               }
+               v2 = nil
+       }
+
+       if v1 != nil {
+               if ir.DeclaredBy(v1, n) {
+                       v1.SetType(t1)
+               } else if v1.Type() != nil {
+                       if op, why := assignop(t1, v1.Type()); op == ir.OXXX {
+                               base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t1, v1, why)
+                       }
+               }
+               checkassign(n, v1)
+       }
+
+       if v2 != nil {
+               if ir.DeclaredBy(v2, n) {
+                       v2.SetType(t2)
+               } else if v2.Type() != nil {
+                       if op, why := assignop(t2, v2.Type()); op == ir.OXXX {
+                               base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t2, v2, why)
+                       }
+               }
+               checkassign(n, v2)
+       }
+}
+
+// select
+func typecheckselect(sel *ir.SelectStmt) {
+       var def ir.Node
+       lno := ir.SetPos(sel)
+       Stmts(sel.Init())
+       for _, ncase := range sel.Cases {
+               ncase := ncase.(*ir.CaseStmt)
+
+               if len(ncase.List) == 0 {
+                       // default
+                       if def != nil {
+                               base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
+                       } else {
+                               def = ncase
+                       }
+               } else if len(ncase.List) > 1 {
+                       base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
+               } else {
+                       ncase.List[0] = Stmt(ncase.List[0])
+                       n := ncase.List[0]
+                       ncase.Comm = n
+                       ncase.List.Set(nil)
+                       oselrecv2 := func(dst, recv ir.Node, colas bool) {
+                               n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil)
+                               n.Lhs = []ir.Node{dst, ir.BlankNode}
+                               n.Rhs = []ir.Node{recv}
+                               n.Def = colas
+                               n.SetTypecheck(1)
+                               ncase.Comm = n
+                       }
+                       switch n.Op() {
+                       default:
+                               pos := n.Pos()
+                               if n.Op() == ir.ONAME {
+                                       // We don't have the right position for ONAME nodes (see #15459 and
+                                       // others). Using ncase.Pos for now as it will provide the correct
+                                       // line number (assuming the expression follows the "case" keyword
+                                       // on the same line). This matches the approach before 1.10.
+                                       pos = ncase.Pos()
+                               }
+                               base.ErrorfAt(pos, "select case must be receive, send or assign recv")
+
+                       case ir.OAS:
+                               // convert x = <-c into x, _ = <-c
+                               // remove implicit conversions; the eventual assignment
+                               // will reintroduce them.
+                               n := n.(*ir.AssignStmt)
+                               if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
+                                       r := r.(*ir.ConvExpr)
+                                       if r.Implicit() {
+                                               n.Y = r.X
+                                       }
+                               }
+                               if n.Y.Op() != ir.ORECV {
+                                       base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
+                                       break
+                               }
+                               oselrecv2(n.X, n.Y, n.Def)
+
+                       case ir.OAS2RECV:
+                               n := n.(*ir.AssignListStmt)
+                               if n.Rhs[0].Op() != ir.ORECV {
+                                       base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
+                                       break
+                               }
+                               n.SetOp(ir.OSELRECV2)
+
+                       case ir.ORECV:
+                               // convert <-c into _, _ = <-c
+                               n := n.(*ir.UnaryExpr)
+                               oselrecv2(ir.BlankNode, n, false)
+
+                       case ir.OSEND:
+                               break
+                       }
+               }
+
+               Stmts(ncase.Body)
+       }
+
+       base.Pos = lno
+}
+
+type typeSet struct {
+       m map[string][]typeSetEntry
+}
+
+func (s *typeSet) add(pos src.XPos, typ *types.Type) {
+       if s.m == nil {
+               s.m = make(map[string][]typeSetEntry)
+       }
+
+       // LongString does not uniquely identify types, so we need to
+       // disambiguate collisions with types.Identical.
+       // TODO(mdempsky): Add a method that *is* unique.
+       ls := typ.LongString()
+       prevs := s.m[ls]
+       for _, prev := range prevs {
+               if types.Identical(typ, prev.typ) {
+                       base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
+                       return
+               }
+       }
+       s.m[ls] = append(prevs, typeSetEntry{pos, typ})
+}
+
+type typeSetEntry struct {
+       pos src.XPos
+       typ *types.Type
+}
+
+func typecheckExprSwitch(n *ir.SwitchStmt) {
+       t := types.Types[types.TBOOL]
+       if n.Tag != nil {
+               n.Tag = Expr(n.Tag)
+               n.Tag = DefaultLit(n.Tag, nil)
+               t = n.Tag.Type()
+       }
+
+       var nilonly string
+       if t != nil {
+               switch {
+               case t.IsMap():
+                       nilonly = "map"
+               case t.Kind() == types.TFUNC:
+                       nilonly = "func"
+               case t.IsSlice():
+                       nilonly = "slice"
+
+               case !types.IsComparable(t):
+                       if t.IsStruct() {
+                               base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
+                       } else {
+                               base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
+                       }
+                       t = nil
+               }
+       }
+
+       var defCase ir.Node
+       var cs constSet
+       for _, ncase := range n.Cases {
+               ncase := ncase.(*ir.CaseStmt)
+               ls := ncase.List
+               if len(ls) == 0 { // default:
+                       if defCase != nil {
+                               base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
+                       } else {
+                               defCase = ncase
+                       }
+               }
+
+               for i := range ls {
+                       ir.SetPos(ncase)
+                       ls[i] = Expr(ls[i])
+                       ls[i] = DefaultLit(ls[i], t)
+                       n1 := ls[i]
+                       if t == nil || n1.Type() == nil {
+                               continue
+                       }
+
+                       if nilonly != "" && !ir.IsNil(n1) {
+                               base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
+                       } else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
+                               base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
+                       } else {
+                               op1, _ := assignop(n1.Type(), t)
+                               op2, _ := assignop(t, n1.Type())
+                               if op1 == ir.OXXX && op2 == ir.OXXX {
+                                       if n.Tag != nil {
+                                               base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
+                                       } else {
+                                               base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
+                                       }
+                               }
+                       }
+
+                       // Don't check for duplicate bools. Although the spec allows it,
+                       // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
+                       // (2) it would disallow useful things like
+                       //       case GOARCH == "arm" && GOARM == "5":
+                       //       case GOARCH == "arm":
+                       //     which would both evaluate to false for non-ARM compiles.
+                       if !n1.Type().IsBoolean() {
+                               cs.add(ncase.Pos(), n1, "case", "switch")
+                       }
+               }
+
+               Stmts(ncase.Body)
+       }
+}
+
+func typecheckTypeSwitch(n *ir.SwitchStmt) {
+       guard := n.Tag.(*ir.TypeSwitchGuard)
+       guard.X = Expr(guard.X)
+       t := guard.X.Type()
+       if t != nil && !t.IsInterface() {
+               base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.X)
+               t = nil
+       }
+
+       // We don't actually declare the type switch's guarded
+       // declaration itself. So if there are no cases, we won't
+       // notice that it went unused.
+       if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
+               base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
+       }
+
+       var defCase, nilCase ir.Node
+       var ts typeSet
+       for _, ncase := range n.Cases {
+               ncase := ncase.(*ir.CaseStmt)
+               ls := ncase.List
+               if len(ls) == 0 { // default:
+                       if defCase != nil {
+                               base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
+                       } else {
+                               defCase = ncase
+                       }
+               }
+
+               for i := range ls {
+                       ls[i] = check(ls[i], ctxExpr|ctxType)
+                       n1 := ls[i]
+                       if t == nil || n1.Type() == nil {
+                               continue
+                       }
+
+                       var missing, have *types.Field
+                       var ptr int
+                       if ir.IsNil(n1) { // case nil:
+                               if nilCase != nil {
+                                       base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
+                               } else {
+                                       nilCase = ncase
+                               }
+                               continue
+                       }
+                       if n1.Op() != ir.OTYPE {
+                               base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
+                               continue
+                       }
+                       if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
+                               if have != nil && !have.Broke() {
+                                       base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
+                                               " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+                               } else if ptr != 0 {
+                                       base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
+                                               " (%v method has pointer receiver)", guard.X, n1.Type(), missing.Sym)
+                               } else {
+                                       base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
+                                               " (missing %v method)", guard.X, n1.Type(), missing.Sym)
+                               }
+                               continue
+                       }
+
+                       ts.add(ncase.Pos(), n1.Type())
+               }
+
+               if len(ncase.Vars) != 0 {
+                       // Assign the clause variable's type.
+                       vt := t
+                       if len(ls) == 1 {
+                               if ls[0].Op() == ir.OTYPE {
+                                       vt = ls[0].Type()
+                               } else if !ir.IsNil(ls[0]) {
+                                       // Invalid single-type case;
+                                       // mark variable as broken.
+                                       vt = nil
+                               }
+                       }
+
+                       nvar := ncase.Vars[0]
+                       nvar.SetType(vt)
+                       if vt != nil {
+                               nvar = AssignExpr(nvar)
+                       } else {
+                               // Clause variable is broken; prevent typechecking.
+                               nvar.SetTypecheck(1)
+                               nvar.SetWalkdef(1)
+                       }
+                       ncase.Vars[0] = nvar
+               }
+
+               Stmts(ncase.Body)
+       }
+}
+
+// typecheckswitch typechecks a switch statement.
+func typecheckswitch(n *ir.SwitchStmt) {
+       Stmts(n.Init())
+       if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
+               typecheckTypeSwitch(n)
+       } else {
+               typecheckExprSwitch(n)
+       }
+}
 
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+       "fmt"
+       "sort"
+       "strconv"
+       "strings"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/src"
+)
+
+func AssignConv(n ir.Node, t *types.Type, context string) ir.Node {
+       return assignconvfn(n, t, func() string { return context })
+}
+
+// DotImportRefs maps idents introduced by importDot back to the
+// ir.PkgName they were dot-imported through.
+var DotImportRefs map[*ir.Ident]*ir.PkgName
+
+// LookupNum looks up the symbol starting with prefix and ending with
+// the decimal n. If prefix is too long, LookupNum panics.
+func LookupNum(prefix string, n int) *types.Sym {
+       var buf [20]byte // plenty long enough for all current users
+       copy(buf[:], prefix)
+       b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
+       return types.LocalPkg.LookupBytes(b)
+}
+
+// Given funarg struct list, return list of fn args.
+func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field {
+       var args []*ir.Field
+       gen := 0
+       for _, t := range tl.Fields().Slice() {
+               s := t.Sym
+               if mustname && (s == nil || s.Name == "_") {
+                       // invent a name so that we can refer to it in the trampoline
+                       s = LookupNum(".anon", gen)
+                       gen++
+               }
+               a := ir.NewField(base.Pos, s, nil, t.Type)
+               a.Pos = t.Pos
+               a.IsDDD = t.IsDDD()
+               args = append(args, a)
+       }
+
+       return args
+}
+
+// newname returns a new ONAME Node associated with symbol s.
+func NewName(s *types.Sym) *ir.Name {
+       n := ir.NewNameAt(base.Pos, s)
+       n.Curfn = ir.CurFunc
+       return n
+}
+
+// NodAddr returns a node representing &n at base.Pos.
+func NodAddr(n ir.Node) *ir.AddrExpr {
+       return NodAddrAt(base.Pos, n)
+}
+
+// nodAddrPos returns a node representing &n at position pos.
+func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
+       return ir.NewAddrExpr(pos, n)
+}
+
+func NodNil() ir.Node {
+       n := ir.NewNilExpr(base.Pos)
+       n.SetType(types.Types[types.TNIL])
+       return n
+}
+
+// in T.field
+// find missing fields that
+// will give shortest unique addressing.
+// modify the tree with missing type names.
+func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr {
+       n.X = check(n.X, ctxType|ctxExpr)
+       if n.X.Diag() {
+               n.SetDiag(true)
+       }
+       t := n.X.Type()
+       if t == nil {
+               return n
+       }
+
+       if n.X.Op() == ir.OTYPE {
+               return n
+       }
+
+       s := n.Sel
+       if s == nil {
+               return n
+       }
+
+       switch path, ambig := dotpath(s, t, nil, false); {
+       case path != nil:
+               // rebuild elided dots
+               for c := len(path) - 1; c >= 0; c-- {
+                       dot := ir.NewSelectorExpr(base.Pos, ir.ODOT, n.X, path[c].field.Sym)
+                       dot.SetImplicit(true)
+                       dot.SetType(path[c].field.Type)
+                       n.X = dot
+               }
+       case ambig:
+               base.Errorf("ambiguous selector %v", n)
+               n.X = nil
+       }
+
+       return n
+}
+
+func CalcMethods(t *types.Type) {
+       if t == nil || t.AllMethods().Len() != 0 {
+               return
+       }
+
+       // mark top-level method symbols
+       // so that expand1 doesn't consider them.
+       for _, f := range t.Methods().Slice() {
+               f.Sym.SetUniq(true)
+       }
+
+       // generate all reachable methods
+       slist = slist[:0]
+       expand1(t, true)
+
+       // check each method to be uniquely reachable
+       var ms []*types.Field
+       for i, sl := range slist {
+               slist[i].field = nil
+               sl.field.Sym.SetUniq(false)
+
+               var f *types.Field
+               path, _ := dotpath(sl.field.Sym, t, &f, false)
+               if path == nil {
+                       continue
+               }
+
+               // dotpath may have dug out arbitrary fields, we only want methods.
+               if !f.IsMethod() {
+                       continue
+               }
+
+               // add it to the base type method list
+               f = f.Copy()
+               f.Embedded = 1 // needs a trampoline
+               for _, d := range path {
+                       if d.field.Type.IsPtr() {
+                               f.Embedded = 2
+                               break
+                       }
+               }
+               ms = append(ms, f)
+       }
+
+       for _, f := range t.Methods().Slice() {
+               f.Sym.SetUniq(false)
+       }
+
+       ms = append(ms, t.Methods().Slice()...)
+       sort.Sort(types.MethodsByName(ms))
+       t.AllMethods().Set(ms)
+}
+
+// adddot1 returns the number of fields or methods named s at depth d in Type t.
+// If exactly one exists, it will be returned in *save (if save is not nil),
+// and dotlist will contain the path of embedded fields traversed to find it,
+// in reverse order. If none exist, more will indicate whether t contains any
+// embedded fields at depth d, so callers can decide whether to retry at
+// a greater depth.
+func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
+       if t.Recur() {
+               return
+       }
+       t.SetRecur(true)
+       defer t.SetRecur(false)
+
+       var u *types.Type
+       d--
+       if d < 0 {
+               // We've reached our target depth. If t has any fields/methods
+               // named s, then we're done. Otherwise, we still need to check
+               // below for embedded fields.
+               c = lookdot0(s, t, save, ignorecase)
+               if c != 0 {
+                       return c, false
+               }
+       }
+
+       u = t
+       if u.IsPtr() {
+               u = u.Elem()
+       }
+       if !u.IsStruct() && !u.IsInterface() {
+               return c, false
+       }
+
+       for _, f := range u.Fields().Slice() {
+               if f.Embedded == 0 || f.Sym == nil {
+                       continue
+               }
+               if d < 0 {
+                       // Found an embedded field at target depth.
+                       return c, true
+               }
+               a, more1 := adddot1(s, f.Type, d, save, ignorecase)
+               if a != 0 && c == 0 {
+                       dotlist[d].field = f
+               }
+               c += a
+               if more1 {
+                       more = true
+               }
+       }
+
+       return c, more
+}
+
+// dotlist is used by adddot1 to record the path of embedded fields
+// used to access a target field or method.
+// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
+var dotlist = make([]dlist, 10)
+
+// Convert node n for assignment to type t.
+func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
+       if n == nil || n.Type() == nil || n.Type().Broke() {
+               return n
+       }
+
+       if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL {
+               base.Errorf("use of untyped nil")
+       }
+
+       n = convlit1(n, t, false, context)
+       if n.Type() == nil {
+               return n
+       }
+       if t.Kind() == types.TBLANK {
+               return n
+       }
+
+       // Convert ideal bool from comparison to plain bool
+       // if the next step is non-bool (like interface{}).
+       if n.Type() == types.UntypedBool && !t.IsBoolean() {
+               if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL {
+                       r := ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
+                       r.SetType(types.Types[types.TBOOL])
+                       r.SetTypecheck(1)
+                       r.SetImplicit(true)
+                       n = r
+               }
+       }
+
+       if types.Identical(n.Type(), t) {
+               return n
+       }
+
+       op, why := assignop(n.Type(), t)
+       if op == ir.OXXX {
+               base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
+               op = ir.OCONV
+       }
+
+       r := ir.NewConvExpr(base.Pos, op, t, n)
+       r.SetTypecheck(1)
+       r.SetImplicit(true)
+       return r
+}
+
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+func assignop(src, dst *types.Type) (ir.Op, string) {
+       if src == dst {
+               return ir.OCONVNOP, ""
+       }
+       if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
+               return ir.OXXX, ""
+       }
+
+       // 1. src type is identical to dst.
+       if types.Identical(src, dst) {
+               return ir.OCONVNOP, ""
+       }
+
+       // 2. src and dst have identical underlying types
+       // and either src or dst is not a named type or
+       // both are empty interface types.
+       // For assignable but different non-empty interface types,
+       // we want to recompute the itab. Recomputing the itab ensures
+       // that itabs are unique (thus an interface with a compile-time
+       // type I has an itab with interface type I).
+       if types.Identical(src.Underlying(), dst.Underlying()) {
+               if src.IsEmptyInterface() {
+                       // Conversion between two empty interfaces
+                       // requires no code.
+                       return ir.OCONVNOP, ""
+               }
+               if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() {
+                       // Conversion between two types, at least one unnamed,
+                       // needs no conversion. The exception is nonempty interfaces
+                       // which need to have their itab updated.
+                       return ir.OCONVNOP, ""
+               }
+       }
+
+       // 3. dst is an interface type and src implements dst.
+       if dst.IsInterface() && src.Kind() != types.TNIL {
+               var missing, have *types.Field
+               var ptr int
+               if implements(src, dst, &missing, &have, &ptr) {
+                       // Call itabname so that (src, dst)
+                       // gets added to itabs early, which allows
+                       // us to de-virtualize calls through this
+                       // type/interface pair later. See peekitabs in reflect.go
+                       if types.IsDirectIface(src) && !dst.IsEmptyInterface() {
+                               NeedITab(src, dst)
+                       }
+
+                       return ir.OCONVIFACE, ""
+               }
+
+               // we'll have complained about this method anyway, suppress spurious messages.
+               if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
+                       return ir.OCONVIFACE, ""
+               }
+
+               var why string
+               if isptrto(src, types.TINTER) {
+                       why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
+               } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
+                       why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
+               } else if have != nil && have.Sym == missing.Sym {
+                       why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
+                               "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+               } else if ptr != 0 {
+                       why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
+               } else if have != nil {
+                       why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
+                               "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+               } else {
+                       why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
+               }
+
+               return ir.OXXX, why
+       }
+
+       if isptrto(dst, types.TINTER) {
+               why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
+               return ir.OXXX, why
+       }
+
+       if src.IsInterface() && dst.Kind() != types.TBLANK {
+               var missing, have *types.Field
+               var ptr int
+               var why string
+               if implements(dst, src, &missing, &have, &ptr) {
+                       why = ": need type assertion"
+               }
+               return ir.OXXX, why
+       }
+
+       // 4. src is a bidirectional channel value, dst is a channel type,
+       // src and dst have identical element types, and
+       // either src or dst is not a named type.
+       if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
+               if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) {
+                       return ir.OCONVNOP, ""
+               }
+       }
+
+       // 5. src is the predeclared identifier nil and dst is a nillable type.
+       if src.Kind() == types.TNIL {
+               switch dst.Kind() {
+               case types.TPTR,
+                       types.TFUNC,
+                       types.TMAP,
+                       types.TCHAN,
+                       types.TINTER,
+                       types.TSLICE:
+                       return ir.OCONVNOP, ""
+               }
+       }
+
+       // 6. rule about untyped constants - already converted by defaultlit.
+
+       // 7. Any typed value can be assigned to the blank identifier.
+       if dst.Kind() == types.TBLANK {
+               return ir.OCONVNOP, ""
+       }
+
+       return ir.OXXX, ""
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+// srcConstant indicates whether the value of type src is a constant.
+func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
+       if src == dst {
+               return ir.OCONVNOP, ""
+       }
+       if src == nil || dst == nil {
+               return ir.OXXX, ""
+       }
+
+       // Conversions from regular to go:notinheap are not allowed
+       // (unless it's unsafe.Pointer). These are runtime-specific
+       // rules.
+       // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
+       if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
+               why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
+               return ir.OXXX, why
+       }
+       // (b) Disallow string to []T where T is go:notinheap.
+       if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) {
+               why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
+               return ir.OXXX, why
+       }
+
+       // 1. src can be assigned to dst.
+       op, why := assignop(src, dst)
+       if op != ir.OXXX {
+               return op, why
+       }
+
+       // The rules for interfaces are no different in conversions
+       // than assignments. If interfaces are involved, stop now
+       // with the good message from assignop.
+       // Otherwise clear the error.
+       if src.IsInterface() || dst.IsInterface() {
+               return ir.OXXX, why
+       }
+
+       // 2. Ignoring struct tags, src and dst have identical underlying types.
+       if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) {
+               return ir.OCONVNOP, ""
+       }
+
+       // 3. src and dst are unnamed pointer types and, ignoring struct tags,
+       // their base types have identical underlying types.
+       if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil {
+               if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) {
+                       return ir.OCONVNOP, ""
+               }
+       }
+
+       // 4. src and dst are both integer or floating point types.
+       if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
+               if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
+                       return ir.OCONVNOP, ""
+               }
+               return ir.OCONV, ""
+       }
+
+       // 5. src and dst are both complex types.
+       if src.IsComplex() && dst.IsComplex() {
+               if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
+                       return ir.OCONVNOP, ""
+               }
+               return ir.OCONV, ""
+       }
+
+       // Special case for constant conversions: any numeric
+       // conversion is potentially okay. We'll validate further
+       // within evconst. See #38117.
+       if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
+               return ir.OCONV, ""
+       }
+
+       // 6. src is an integer or has type []byte or []rune
+       // and dst is a string type.
+       if src.IsInteger() && dst.IsString() {
+               return ir.ORUNESTR, ""
+       }
+
+       if src.IsSlice() && dst.IsString() {
+               if src.Elem().Kind() == types.ByteType.Kind() {
+                       return ir.OBYTES2STR, ""
+               }
+               if src.Elem().Kind() == types.RuneType.Kind() {
+                       return ir.ORUNES2STR, ""
+               }
+       }
+
+       // 7. src is a string and dst is []byte or []rune.
+       // String to slice.
+       if src.IsString() && dst.IsSlice() {
+               if dst.Elem().Kind() == types.ByteType.Kind() {
+                       return ir.OSTR2BYTES, ""
+               }
+               if dst.Elem().Kind() == types.RuneType.Kind() {
+                       return ir.OSTR2RUNES, ""
+               }
+       }
+
+       // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+       if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
+               return ir.OCONVNOP, ""
+       }
+
+       // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
+       if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
+               return ir.OCONVNOP, ""
+       }
+
+       // src is map and dst is a pointer to corresponding hmap.
+       // This rule is needed for the implementation detail that
+       // go gc maps are implemented as a pointer to a hmap struct.
+       if src.Kind() == types.TMAP && dst.IsPtr() &&
+               src.MapType().Hmap == dst.Elem() {
+               return ir.OCONVNOP, ""
+       }
+
+       return ir.OXXX, ""
+}
+
+// Code to resolve elided DOTs in embedded types.
+
+// A dlist stores a pointer to a TFIELD Type embedded within
+// a TSTRUCT or TINTER Type.
+type dlist struct {
+       field *types.Field
+}
+
+// dotpath computes the unique shortest explicit selector path to fully qualify
+// a selection expression x.f, where x is of type t and f is the symbol s.
+// If no such path exists, dotpath returns nil.
+// If there are multiple shortest paths to the same depth, ambig is true.
+func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []dlist, ambig bool) {
+       // The embedding of types within structs imposes a tree structure onto
+       // types: structs parent the types they embed, and types parent their
+       // fields or methods. Our goal here is to find the shortest path to
+       // a field or method named s in the subtree rooted at t. To accomplish
+       // that, we iteratively perform depth-first searches of increasing depth
+       // until we either find the named field/method or exhaust the tree.
+       for d := 0; ; d++ {
+               if d > len(dotlist) {
+                       dotlist = append(dotlist, dlist{})
+               }
+               if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
+                       return dotlist[:d], false
+               } else if c > 1 {
+                       return nil, true
+               } else if !more {
+                       return nil, false
+               }
+       }
+}
+
+func expand0(t *types.Type) {
+       u := t
+       if u.IsPtr() {
+               u = u.Elem()
+       }
+
+       if u.IsInterface() {
+               for _, f := range u.Fields().Slice() {
+                       if f.Sym.Uniq() {
+                               continue
+                       }
+                       f.Sym.SetUniq(true)
+                       slist = append(slist, symlink{field: f})
+               }
+
+               return
+       }
+
+       u = types.ReceiverBaseType(t)
+       if u != nil {
+               for _, f := range u.Methods().Slice() {
+                       if f.Sym.Uniq() {
+                               continue
+                       }
+                       f.Sym.SetUniq(true)
+                       slist = append(slist, symlink{field: f})
+               }
+       }
+}
+
+func expand1(t *types.Type, top bool) {
+       if t.Recur() {
+               return
+       }
+       t.SetRecur(true)
+
+       if !top {
+               expand0(t)
+       }
+
+       u := t
+       if u.IsPtr() {
+               u = u.Elem()
+       }
+
+       if u.IsStruct() || u.IsInterface() {
+               for _, f := range u.Fields().Slice() {
+                       if f.Embedded == 0 {
+                               continue
+                       }
+                       if f.Sym == nil {
+                               continue
+                       }
+                       expand1(f.Type, false)
+               }
+       }
+
+       t.SetRecur(false)
+}
+
+func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
+       if t == nil {
+               return nil, false
+       }
+
+       path, ambig := dotpath(s, t, &m, ignorecase)
+       if path == nil {
+               if ambig {
+                       base.Errorf("%v.%v is ambiguous", t, s)
+               }
+               return nil, false
+       }
+
+       for _, d := range path {
+               if d.field.Type.IsPtr() {
+                       followptr = true
+                       break
+               }
+       }
+
+       if !m.IsMethod() {
+               base.Errorf("%v.%v is a field, not a method", t, s)
+               return nil, followptr
+       }
+
+       return m, followptr
+}
+
+func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
+       t0 := t
+       if t == nil {
+               return false
+       }
+
+       if t.IsInterface() {
+               i := 0
+               tms := t.Fields().Slice()
+               for _, im := range iface.Fields().Slice() {
+                       for i < len(tms) && tms[i].Sym != im.Sym {
+                               i++
+                       }
+                       if i == len(tms) {
+                               *m = im
+                               *samename = nil
+                               *ptr = 0
+                               return false
+                       }
+                       tm := tms[i]
+                       if !types.Identical(tm.Type, im.Type) {
+                               *m = im
+                               *samename = tm
+                               *ptr = 0
+                               return false
+                       }
+               }
+
+               return true
+       }
+
+       t = types.ReceiverBaseType(t)
+       var tms []*types.Field
+       if t != nil {
+               CalcMethods(t)
+               tms = t.AllMethods().Slice()
+       }
+       i := 0
+       for _, im := range iface.Fields().Slice() {
+               if im.Broke() {
+                       continue
+               }
+               for i < len(tms) && tms[i].Sym != im.Sym {
+                       i++
+               }
+               if i == len(tms) {
+                       *m = im
+                       *samename, _ = ifacelookdot(im.Sym, t, true)
+                       *ptr = 0
+                       return false
+               }
+               tm := tms[i]
+               if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
+                       *m = im
+                       *samename = tm
+                       *ptr = 0
+                       return false
+               }
+               followptr := tm.Embedded == 2
+
+               // if pointer receiver in method,
+               // the method does not exist for value types.
+               rcvr := tm.Type.Recv().Type
+               if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) {
+                       if false && base.Flag.LowerR != 0 {
+                               base.Errorf("interface pointer mismatch")
+                       }
+
+                       *m = im
+                       *samename = nil
+                       *ptr = 1
+                       return false
+               }
+       }
+
+       return true
+}
+
+func isptrto(t *types.Type, et types.Kind) bool {
+       if t == nil {
+               return false
+       }
+       if !t.IsPtr() {
+               return false
+       }
+       t = t.Elem()
+       if t == nil {
+               return false
+       }
+       if t.Kind() != et {
+               return false
+       }
+       return true
+}
+
+// lookdot0 returns the number of fields or methods named s associated
+// with Type t. If exactly one exists, it will be returned in *save
+// (if save is not nil).
+func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
+       u := t
+       if u.IsPtr() {
+               u = u.Elem()
+       }
+
+       c := 0
+       if u.IsStruct() || u.IsInterface() {
+               for _, f := range u.Fields().Slice() {
+                       if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
+                               if save != nil {
+                                       *save = f
+                               }
+                               c++
+                       }
+               }
+       }
+
+       u = t
+       if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() {
+               // If t is a defined pointer type, then x.m is shorthand for (*x).m.
+               u = t.Elem()
+       }
+       u = types.ReceiverBaseType(u)
+       if u != nil {
+               for _, f := range u.Methods().Slice() {
+                       if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
+                               if save != nil {
+                                       *save = f
+                               }
+                               c++
+                       }
+               }
+       }
+
+       return c
+}
+
+var slist []symlink
+
+// Code to help generate trampoline functions for methods on embedded
+// types. These are approx the same as the corresponding adddot
+// routines except that they expect to be called with unique tasks and
+// they return the actual methods.
+
+type symlink struct {
+       field *types.Field
+}
 
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
+       "cmd/internal/obj"
+       "cmd/internal/src"
+)
+
+func LookupRuntime(name string) *ir.Name {
+       s := ir.Pkgs.Runtime.Lookup(name)
+       if s == nil || s.Def == nil {
+               base.Fatalf("syslook: can't find runtime.%s", name)
+       }
+       return ir.AsNode(s.Def).(*ir.Name)
+}
+
+// SubstArgTypes substitutes the given list of types for
+// successive occurrences of the "any" placeholder in the
+// type syntax expression n.Type.
+// The result of SubstArgTypes MUST be assigned back to old, e.g.
+//     n.Left = SubstArgTypes(n.Left, t1, t2)
+func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
+       n := old.CloneName()
+
+       for _, t := range types_ {
+               types.CalcSize(t)
+       }
+       n.SetType(types.SubstAny(n.Type(), &types_))
+       if len(types_) > 0 {
+               base.Fatalf("substArgTypes: too many argument types")
+       }
+       return n
+}
+
+// AutoLabel generates a new Name node for use with
+// an automatically generated label.
+// prefix is a short mnemonic (e.g. ".s" for switch)
+// to help with debugging.
+// It should begin with "." to avoid conflicts with
+// user labels.
+func AutoLabel(prefix string) *types.Sym {
+       if prefix[0] != '.' {
+               base.Fatalf("autolabel prefix must start with '.', have %q", prefix)
+       }
+       fn := ir.CurFunc
+       if ir.CurFunc == nil {
+               base.Fatalf("autolabel outside function")
+       }
+       n := fn.Label
+       fn.Label++
+       return LookupNum(prefix, int(n))
+}
+
+func Lookup(name string) *types.Sym {
+       return types.LocalPkg.Lookup(name)
+}
+
+// loadsys loads the definitions for the low-level runtime functions,
+// so that the compiler can generate calls to them,
+// but does not make them visible to user code.
+func loadsys() {
+       types.Block = 1
+
+       inimport = true
+       TypecheckAllowed = true
+
+       typs := runtimeTypes()
+       for _, d := range &runtimeDecls {
+               sym := ir.Pkgs.Runtime.Lookup(d.name)
+               typ := typs[d.typ]
+               switch d.tag {
+               case funcTag:
+                       importfunc(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
+               case varTag:
+                       importvar(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
+               default:
+                       base.Fatalf("unhandled declaration tag %v", d.tag)
+               }
+       }
+
+       TypecheckAllowed = false
+       inimport = false
+}
+
+// LookupRuntimeFunc looks up Go function name in package runtime. This function
+// must follow the internal calling convention.
+func LookupRuntimeFunc(name string) *obj.LSym {
+       s := ir.Pkgs.Runtime.Lookup(name)
+       s.SetFunc(true)
+       return s.Linksym()
+}
+
+// LookupRuntimeVar looks up a variable (or assembly function) name in package
+// runtime. If this is a function, it may have a special calling
+// convention.
+func LookupRuntimeVar(name string) *obj.LSym {
+       return ir.Pkgs.Runtime.Lookup(name).Linksym()
+}
 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+//go:generate go run mkbuiltin.go
+
+package typecheck
+
+import "cmd/compile/internal/ir"
+
+// Target is the package being compiled.
+var Target *ir.Package
 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package typecheck
 
 import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
        "fmt"
        "go/constant"
        "go/token"
        "strings"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
 )
 
+// Function collecting autotmps generated during typechecking,
+// to be included in the package-level init function.
+var InitTodoFunc = ir.NewFunc(base.Pos)
+
+var inimport bool // set during import
+
+var decldepth int32
+
+var TypecheckAllowed bool
+
 var (
        NeedFuncSym     = func(*types.Sym) {}
        NeedITab        = func(t, itype *types.Type) {}
        NeedRuntimeType = func(*types.Type) {}
 )
 
-func TypecheckInit() {
+func Init() {
        initUniverse()
-       dclcontext = ir.PEXTERN
+       DeclContext = ir.PEXTERN
        base.Timer.Start("fe", "loadsys")
        loadsys()
 }
 
-func TypecheckPackage() {
-       finishUniverse()
+func Package() {
+       declareUniverse()
 
-       typecheckok = true
+       TypecheckAllowed = true
 
        // Process top-level declarations in phases.
 
        for i := 0; i < len(Target.Decls); i++ {
                n := Target.Decls[i]
                if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).X.Name().Alias()) {
-                       Target.Decls[i] = typecheck(n, ctxStmt)
+                       Target.Decls[i] = Stmt(n)
                }
        }
 
        for i := 0; i < len(Target.Decls); i++ {
                n := Target.Decls[i]
                if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Name().Alias() {
-                       Target.Decls[i] = typecheck(n, ctxStmt)
+                       Target.Decls[i] = Stmt(n)
                }
        }
 
        for i := 0; i < len(Target.Decls); i++ {
                n := Target.Decls[i]
                if n.Op() == ir.ODCLFUNC {
-                       TypecheckFuncBody(n.(*ir.Func))
+                       FuncBody(n.(*ir.Func))
                        fcount++
                }
        }
        base.Timer.Start("fe", "typecheck", "externdcls")
        for i, n := range Target.Externs {
                if n.Op() == ir.ONAME {
-                       Target.Externs[i] = typecheck(Target.Externs[i], ctxExpr)
+                       Target.Externs[i] = Expr(Target.Externs[i])
                }
        }
 
        // Phase 5: With all user code type-checked, it's now safe to verify map keys.
-       checkMapKeys()
+       CheckMapKeys()
 
        // Phase 6: Decide how to capture closed variables.
        // This needs to run before escape analysis,
                        n := n.(*ir.Func)
                        if n.OClosure != nil {
                                ir.CurFunc = n
-                               capturevars(n)
+                               CaptureVars(n)
                        }
                }
        }
-       capturevarscomplete = true
+       CaptureVarsComplete = true
        ir.CurFunc = nil
 
        if base.Debug.TypecheckInl != 0 {
                // Typecheck imported function bodies if Debug.l > 1,
                // otherwise lazily when used or re-exported.
-               TypecheckImports()
+               AllImportedBodies()
        }
 }
 
-func TypecheckAssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
-func TypecheckExpr(n ir.Node) ir.Node       { return typecheck(n, ctxExpr) }
-func TypecheckStmt(n ir.Node) ir.Node       { return typecheck(n, ctxStmt) }
+func AssignExpr(n ir.Node) ir.Node { return check(n, ctxExpr|ctxAssign) }
+func Expr(n ir.Node) ir.Node       { return check(n, ctxExpr) }
+func Stmt(n ir.Node) ir.Node       { return check(n, ctxStmt) }
 
-func TypecheckExprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) }
-func TypecheckStmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) }
+func Exprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) }
+func Stmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) }
 
-func TypecheckCall(call *ir.CallExpr) {
+func Call(call *ir.CallExpr) {
        t := call.X.Type()
        if t == nil {
                panic("misuse of Call")
        if t.NumResults() > 0 {
                ctx = ctxExpr | ctxMultiOK
        }
-       if typecheck(call, ctx) != call {
+       if check(call, ctx) != call {
                panic("bad typecheck")
        }
 }
 
-func TypecheckCallee(n ir.Node) ir.Node {
-       return typecheck(n, ctxExpr|ctxCallee)
+func Callee(n ir.Node) ir.Node {
+       return check(n, ctxExpr|ctxCallee)
 }
 
-func TypecheckFuncBody(n *ir.Func) {
+func FuncBody(n *ir.Func) {
        ir.CurFunc = n
        decldepth = 1
        errorsBefore := base.Errors()
-       typecheckslice(n.Body, ctxStmt)
-       checkreturn(n)
+       Stmts(n.Body)
+       CheckReturn(n)
        if base.Errors() > errorsBefore {
                n.Body.Set(nil) // type errors; do not compile
        }
 
 var importlist []*ir.Func
 
-func TypecheckImports() {
+func AllImportedBodies() {
        for _, n := range importlist {
                if n.Inl != nil {
-                       typecheckinl(n)
+                       ImportedBody(n)
                }
        }
 }
 
 var typecheckdefstack []ir.Node
 
-// resolve ONONAME to definition, if any.
-func resolve(n ir.Node) (res ir.Node) {
+// Resolve ONONAME to definition, if any.
+func Resolve(n ir.Node) (res ir.Node) {
        if n == nil || n.Op() != ir.ONONAME {
                return n
        }
        if sym := n.Sym(); sym.Pkg != types.LocalPkg {
                // We might have an ir.Ident from oldname or importDot.
                if id, ok := n.(*ir.Ident); ok {
-                       if pkgName := dotImportRefs[id]; pkgName != nil {
+                       if pkgName := DotImportRefs[id]; pkgName != nil {
                                pkgName.Used = true
                        }
                }
 
 func typecheckslice(l []ir.Node, top int) {
        for i := range l {
-               l[i] = typecheck(l[i], top)
+               l[i] = check(l[i], top)
        }
 }
 
 
 var typecheck_tcstack []ir.Node
 
-func typecheckFunc(fn *ir.Func) {
-       new := typecheck(fn, ctxStmt)
+func Func(fn *ir.Func) {
+       new := Stmt(fn)
        if new != fn {
                base.Fatalf("typecheck changed func")
        }
 }
 
 func typecheckNtype(n ir.Ntype) ir.Ntype {
-       return typecheck(n, ctxType).(ir.Ntype)
+       return check(n, ctxType).(ir.Ntype)
 }
 
-// typecheck type checks node n.
-// The result of typecheck MUST be assigned back to n, e.g.
-//     n.Left = typecheck(n.Left, top)
-func typecheck(n ir.Node, top int) (res ir.Node) {
+// check type checks node n.
+// The result of check MUST be assigned back to n, e.g.
+//     n.Left = check(n.Left, top)
+func check(n ir.Node, top int) (res ir.Node) {
        // cannot type check until all the source has been parsed
-       if !typecheckok {
+       if !TypecheckAllowed {
                base.Fatalf("early typecheck")
        }
 
        }
 
        // Resolve definition of name and value of iota lazily.
-       n = resolve(n)
+       n = Resolve(n)
 
        // Skip typecheck if already done.
        // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
                }
        }
        if t != nil {
-               n = evalConst(n)
+               n = EvalConst(n)
                t = n.Type()
        }
 
 //     n.Left = indexlit(n.Left)
 func indexlit(n ir.Node) ir.Node {
        if n != nil && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
-               return defaultlit(n, types.Types[types.TINT])
+               return DefaultLit(n, types.Types[types.TINT])
        }
        return n
 }
 
        case ir.OTSLICE:
                n := n.(*ir.SliceType)
-               n.Elem = typecheck(n.Elem, ctxType)
+               n.Elem = check(n.Elem, ctxType)
                if n.Elem.Type() == nil {
                        return n
                }
 
        case ir.OTARRAY:
                n := n.(*ir.ArrayType)
-               n.Elem = typecheck(n.Elem, ctxType)
+               n.Elem = check(n.Elem, ctxType)
                if n.Elem.Type() == nil {
                        return n
                }
                        }
                        return n
                }
-               n.Len = indexlit(typecheck(n.Len, ctxExpr))
+               n.Len = indexlit(Expr(n.Len))
                size := n.Len
                if ir.ConstType(size) != constant.Int {
                        switch {
 
        case ir.OTMAP:
                n := n.(*ir.MapType)
-               n.Key = typecheck(n.Key, ctxType)
-               n.Elem = typecheck(n.Elem, ctxType)
+               n.Key = check(n.Key, ctxType)
+               n.Elem = check(n.Elem, ctxType)
                l := n.Key
                r := n.Elem
                if l.Type() == nil || r.Type() == nil {
 
        case ir.OTCHAN:
                n := n.(*ir.ChanType)
-               n.Elem = typecheck(n.Elem, ctxType)
+               n.Elem = check(n.Elem, ctxType)
                l := n.Elem
                if l.Type() == nil {
                        return n
 
        case ir.OTSTRUCT:
                n := n.(*ir.StructType)
-               n.SetOTYPE(tostruct(n.Fields))
+               n.SetOTYPE(NewStructType(n.Fields))
                return n
 
        case ir.OTINTER:
 
        case ir.OTFUNC:
                n := n.(*ir.FuncType)
-               n.SetOTYPE(functype(n.Recv, n.Params, n.Results))
+               n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results))
                return n
 
        // type or expr
        case ir.ODEREF:
                n := n.(*ir.StarExpr)
-               n.X = typecheck(n.X, ctxExpr|ctxType)
+               n.X = check(n.X, ctxExpr|ctxType)
                l := n.X
                t := l.Type()
                if t == nil {
                        l, r = n.X, n.Y
                        setLR = func() { n.X = l; n.Y = r }
                }
-               l = typecheck(l, ctxExpr)
-               r = typecheck(r, ctxExpr)
+               l = Expr(l)
+               r = Expr(r)
                setLR()
                if l.Type() == nil || r.Type() == nil {
                        n.SetType(nil)
                        op = n.AsOp
                }
                if op == ir.OLSH || op == ir.ORSH {
-                       r = defaultlit(r, types.Types[types.TUINT])
+                       r = DefaultLit(r, types.Types[types.TUINT])
                        setLR()
                        t := r.Type()
                        if !t.IsInteger() {
                if iscmp[n.Op()] {
                        t = types.UntypedBool
                        n.SetType(t)
-                       if con := evalConst(n); con.Op() == ir.OLITERAL {
+                       if con := EvalConst(n); con.Op() == ir.OLITERAL {
                                return con
                        }
                        l, r = defaultlit2(l, r, true)
 
        case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                l := n.X
                t := l.Type()
                if t == nil {
        // exprs
        case ir.OADDR:
                n := n.(*ir.AddrExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                if n.X.Type() == nil {
                        n.SetType(nil)
                        return n
                                        base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
                                }
                                r.Name().SetAddrtaken(true)
-                               if r.Name().IsClosureVar() && !capturevarscomplete {
+                               if r.Name().IsClosureVar() && !CaptureVarsComplete {
                                        // Mark the original variable as Addrtaken so that capturevars
                                        // knows not to pass it by value.
                                        // But if the capturevars phase is complete, don't touch it,
                                        r.Name().Defn.Name().SetAddrtaken(true)
                                }
                        }
-                       n.X = defaultlit(n.X, nil)
+                       n.X = DefaultLit(n.X, nil)
                        if n.X.Type() == nil {
                                n.SetType(nil)
                                return n
        case ir.OXDOT, ir.ODOT:
                n := n.(*ir.SelectorExpr)
                if n.Op() == ir.OXDOT {
-                       n = adddot(n)
+                       n = AddImplicitDots(n)
                        n.SetOp(ir.ODOT)
                        if n.X == nil {
                                n.SetType(nil)
                        }
                }
 
-               n.X = typecheck(n.X, ctxExpr|ctxType)
+               n.X = check(n.X, ctxExpr|ctxType)
 
-               n.X = defaultlit(n.X, nil)
+               n.X = DefaultLit(n.X, nil)
 
                t := n.X.Type()
                if t == nil {
 
        case ir.ODOTTYPE:
                n := n.(*ir.TypeAssertExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
                l := n.X
                t := l.Type()
                if t == nil {
                }
 
                if n.Ntype != nil {
-                       n.Ntype = typecheck(n.Ntype, ctxType)
+                       n.Ntype = check(n.Ntype, ctxType)
                        n.SetType(n.Ntype.Type())
                        n.Ntype = nil
                        if n.Type() == nil {
 
        case ir.OINDEX:
                n := n.(*ir.IndexExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
                n.X = implicitstar(n.X)
                l := n.X
-               n.Index = typecheck(n.Index, ctxExpr)
+               n.Index = Expr(n.Index)
                r := n.Index
                t := l.Type()
                if t == nil || r.Type() == nil {
                        }
 
                case types.TMAP:
-                       n.Index = assignconv(n.Index, t.Key(), "map index")
+                       n.Index = AssignConv(n.Index, t.Key(), "map index")
                        n.SetType(t.Elem())
                        n.SetOp(ir.OINDEXMAP)
                        n.Assigned = false
 
        case ir.ORECV:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
                l := n.X
                t := l.Type()
                if t == nil {
 
        case ir.OSEND:
                n := n.(*ir.SendStmt)
-               n.Chan = typecheck(n.Chan, ctxExpr)
-               n.Value = typecheck(n.Value, ctxExpr)
-               n.Chan = defaultlit(n.Chan, nil)
+               n.Chan = Expr(n.Chan)
+               n.Value = Expr(n.Value)
+               n.Chan = DefaultLit(n.Chan, nil)
                t := n.Chan.Type()
                if t == nil {
                        return n
                        return n
                }
 
-               n.Value = assignconv(n.Value, t.Elem(), "send")
+               n.Value = AssignConv(n.Value, t.Elem(), "send")
                if n.Value.Type() == nil {
                        return n
                }
                        base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
                }
 
-               n.Ptr = typecheck(n.Ptr, ctxExpr)
-               l := typecheck(n.LenCap[0], ctxExpr)
-               c := typecheck(n.LenCap[1], ctxExpr)
-               l = defaultlit(l, types.Types[types.TINT])
-               c = defaultlit(c, types.Types[types.TINT])
+               n.Ptr = Expr(n.Ptr)
+               l := Expr(n.LenCap[0])
+               c := Expr(n.LenCap[1])
+               l = DefaultLit(l, types.Types[types.TINT])
+               c = DefaultLit(c, types.Types[types.TINT])
 
                if ir.IsConst(l, constant.Int) && ir.Int64Val(l) < 0 {
                        base.Fatalf("len for OSLICEHEADER must be non-negative")
                        base.Fatalf("missing slice argument to copy for OMAKESLICECOPY")
                }
 
-               n.Len = typecheck(n.Len, ctxExpr)
-               n.Cap = typecheck(n.Cap, ctxExpr)
+               n.Len = Expr(n.Len)
+               n.Cap = Expr(n.Cap)
 
-               n.Len = defaultlit(n.Len, types.Types[types.TINT])
+               n.Len = DefaultLit(n.Len, types.Types[types.TINT])
 
                if !n.Len.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
                        base.Errorf("non-integer len argument in OMAKESLICECOPY")
 
        case ir.OSLICE, ir.OSLICE3:
                n := n.(*ir.SliceExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                low, high, max := n.SliceBounds()
                hasmax := n.Op().IsSlice3()
-               low = typecheck(low, ctxExpr)
-               high = typecheck(high, ctxExpr)
-               max = typecheck(max, ctxExpr)
-               n.X = defaultlit(n.X, nil)
+               low = Expr(low)
+               high = Expr(high)
+               max = Expr(max)
+               n.X = DefaultLit(n.X, nil)
                low = indexlit(low)
                high = indexlit(high)
                max = indexlit(max)
                                return n
                        }
 
-                       addr := nodAddr(n.X)
+                       addr := NodAddr(n.X)
                        addr.SetImplicit(true)
-                       n.X = typecheck(addr, ctxExpr)
+                       n.X = Expr(addr)
                        l = n.X
                }
                t := l.Type()
                if top == ctxStmt {
                        n.Use = ir.CallUseStmt
                }
-               typecheckslice(n.Init(), ctxStmt) // imported rewritten f(g()) calls (#30907)
-               n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee)
+               Stmts(n.Init()) // imported rewritten f(g()) calls (#30907)
+               n.X = check(n.X, ctxExpr|ctxType|ctxCallee)
                if n.X.Diag() {
                        n.SetDiag(true)
                }
                                n.SetOp(l.BuiltinOp)
                                n.X = nil
                                n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
-                               return typecheck(n, top)
+                               return check(n, top)
 
                        case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
                                typecheckargs(n)
                                        return n
                                }
                                u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
-                               return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
+                               return check(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
 
                        case ir.OCOMPLEX, ir.OCOPY:
                                typecheckargs(n)
                                        return n
                                }
                                b := ir.NewBinaryExpr(n.Pos(), l.BuiltinOp, arg1, arg2)
-                               return typecheck(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
+                               return check(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
                        }
                        panic("unreachable")
                }
 
-               n.X = defaultlit(n.X, nil)
+               n.X = DefaultLit(n.X, nil)
                l = n.X
                if l.Op() == ir.OTYPE {
                        if n.IsDDD {
 
        case ir.OCAP, ir.OLEN:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
                n.X = implicitstar(n.X)
                l := n.X
                t := l.Type()
 
        case ir.OREAL, ir.OIMAG:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                l := n.X
                t := l.Type()
                if t == nil {
 
        case ir.OCOMPLEX:
                n := n.(*ir.BinaryExpr)
-               l := typecheck(n.X, ctxExpr)
-               r := typecheck(n.Y, ctxExpr)
+               l := Expr(n.X)
+               r := Expr(n.Y)
                if l.Type() == nil || r.Type() == nil {
                        n.SetType(nil)
                        return n
 
        case ir.OCLOSE:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
                l := n.X
                t := l.Type()
                if t == nil {
                        return n
                }
 
-               args[1] = assignconv(r, l.Type().Key(), "delete")
+               args[1] = AssignConv(r, l.Type().Key(), "delete")
                return n
 
        case ir.OAPPEND:
                        }
 
                        if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
-                               args[1] = defaultlit(args[1], types.Types[types.TSTRING])
+                               args[1] = DefaultLit(args[1], types.Types[types.TSTRING])
                                return n
                        }
 
-                       args[1] = assignconv(args[1], t.Underlying(), "append")
+                       args[1] = AssignConv(args[1], t.Underlying(), "append")
                        return n
                }
 
                        if n.Type() == nil {
                                continue
                        }
-                       as[i] = assignconv(n, t.Elem(), "append")
+                       as[i] = AssignConv(n, t.Elem(), "append")
                        types.CheckSize(as[i].Type()) // ensure width is calculated for backend
                }
                return n
        case ir.OCOPY:
                n := n.(*ir.BinaryExpr)
                n.SetType(types.Types[types.TINT])
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, nil)
-               n.Y = typecheck(n.Y, ctxExpr)
-               n.Y = defaultlit(n.Y, nil)
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, nil)
+               n.Y = Expr(n.Y)
+               n.Y = DefaultLit(n.Y, nil)
                if n.X.Type() == nil || n.Y.Type() == nil {
                        n.SetType(nil)
                        return n
        case ir.OCONV:
                n := n.(*ir.ConvExpr)
                types.CheckSize(n.Type()) // ensure width is calculated for backend
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                n.X = convlit1(n.X, n.Type(), true, nil)
                t := n.X.Type()
                if t == nil || n.Type() == nil {
 
                n.Args.Set(nil)
                l := args[0]
-               l = typecheck(l, ctxType)
+               l = check(l, ctxType)
                t := l.Type()
                if t == nil {
                        n.SetType(nil)
 
                        l = args[i]
                        i++
-                       l = typecheck(l, ctxExpr)
+                       l = Expr(l)
                        var r ir.Node
                        if i < len(args) {
                                r = args[i]
                                i++
-                               r = typecheck(r, ctxExpr)
+                               r = Expr(r)
                        }
 
                        if l.Type() == nil || (r != nil && r.Type() == nil) {
                        if i < len(args) {
                                l = args[i]
                                i++
-                               l = typecheck(l, ctxExpr)
-                               l = defaultlit(l, types.Types[types.TINT])
+                               l = Expr(l)
+                               l = DefaultLit(l, types.Types[types.TINT])
                                if l.Type() == nil {
                                        n.SetType(nil)
                                        return n
                        if i < len(args) {
                                l = args[i]
                                i++
-                               l = typecheck(l, ctxExpr)
-                               l = defaultlit(l, types.Types[types.TINT])
+                               l = Expr(l)
+                               l = DefaultLit(l, types.Types[types.TINT])
                                if l.Type() == nil {
                                        n.SetType(nil)
                                        return n
                        base.Fatalf("missing argument to new")
                }
                l := n.X
-               l = typecheck(l, ctxType)
+               l = check(l, ctxType)
                t := l.Type()
                if t == nil {
                        n.SetType(nil)
                for i1, n1 := range ls {
                        // Special case for print: int constant is int64, not int.
                        if ir.IsConst(n1, constant.Int) {
-                               ls[i1] = defaultlit(ls[i1], types.Types[types.TINT64])
+                               ls[i1] = DefaultLit(ls[i1], types.Types[types.TINT64])
                        } else {
-                               ls[i1] = defaultlit(ls[i1], nil)
+                               ls[i1] = DefaultLit(ls[i1], nil)
                        }
                }
                return n
 
        case ir.OPANIC:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
-               n.X = defaultlit(n.X, types.Types[types.TINTER])
+               n.X = Expr(n.X)
+               n.X = DefaultLit(n.X, types.Types[types.TINTER])
                if n.X.Type() == nil {
                        n.SetType(nil)
                        return n
 
        case ir.OITAB:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                t := n.X.Type()
                if t == nil {
                        n.SetType(nil)
 
        case ir.OSPTR:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                t := n.X.Type()
                if t == nil {
                        n.SetType(nil)
 
        case ir.OCFUNC:
                n := n.(*ir.UnaryExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                n.SetType(types.Types[types.TUINTPTR])
                return n
 
        case ir.OCONVNOP:
                n := n.(*ir.ConvExpr)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                return n
 
        // statements
 
        case ir.OBLOCK:
                n := n.(*ir.BlockStmt)
-               typecheckslice(n.List, ctxStmt)
+               Stmts(n.List)
                return n
 
        case ir.OLABEL:
 
        case ir.ODEFER, ir.OGO:
                n := n.(*ir.GoDeferStmt)
-               n.Call = typecheck(n.Call, ctxStmt|ctxExpr)
+               n.Call = check(n.Call, ctxStmt|ctxExpr)
                if !n.Call.Diag() {
                        checkdefergo(n)
                }
 
        case ir.OFOR, ir.OFORUNTIL:
                n := n.(*ir.ForStmt)
-               typecheckslice(n.Init(), ctxStmt)
+               Stmts(n.Init())
                decldepth++
-               n.Cond = typecheck(n.Cond, ctxExpr)
-               n.Cond = defaultlit(n.Cond, nil)
+               n.Cond = Expr(n.Cond)
+               n.Cond = DefaultLit(n.Cond, nil)
                if n.Cond != nil {
                        t := n.Cond.Type()
                        if t != nil && !t.IsBoolean() {
                                base.Errorf("non-bool %L used as for condition", n.Cond)
                        }
                }
-               n.Post = typecheck(n.Post, ctxStmt)
+               n.Post = Stmt(n.Post)
                if n.Op() == ir.OFORUNTIL {
-                       typecheckslice(n.Late, ctxStmt)
+                       Stmts(n.Late)
                }
-               typecheckslice(n.Body, ctxStmt)
+               Stmts(n.Body)
                decldepth--
                return n
 
        case ir.OIF:
                n := n.(*ir.IfStmt)
-               typecheckslice(n.Init(), ctxStmt)
-               n.Cond = typecheck(n.Cond, ctxExpr)
-               n.Cond = defaultlit(n.Cond, nil)
+               Stmts(n.Init())
+               n.Cond = Expr(n.Cond)
+               n.Cond = DefaultLit(n.Cond, nil)
                if n.Cond != nil {
                        t := n.Cond.Type()
                        if t != nil && !t.IsBoolean() {
                                base.Errorf("non-bool %L used as if condition", n.Cond)
                        }
                }
-               typecheckslice(n.Body, ctxStmt)
-               typecheckslice(n.Else, ctxStmt)
+               Stmts(n.Body)
+               Stmts(n.Else)
                return n
 
        case ir.ORETURN:
 
        case ir.ODCLCONST:
                n := n.(*ir.Decl)
-               n.X = typecheck(n.X, ctxExpr)
+               n.X = Expr(n.X)
                return n
 
        case ir.ODCLTYPE:
                n := n.(*ir.Decl)
-               n.X = typecheck(n.X, ctxType)
+               n.X = check(n.X, ctxType)
                types.CheckSize(n.X.Type())
                return n
        }
        case *ir.CallExpr:
                list = n.Args
                if n.IsDDD {
-                       typecheckslice(list, ctxExpr)
+                       Exprs(list)
                        return
                }
        case *ir.ReturnStmt:
                list = n.Results
        }
        if len(list) != 1 {
-               typecheckslice(list, ctxExpr)
+               Exprs(list)
                return
        }
 
        // will reassociate them later when it's appropriate.
        static := ir.CurFunc == nil
        if static {
-               ir.CurFunc = initTodo
+               ir.CurFunc = InitTodoFunc
        }
        list = nil
        for _, f := range t.FieldSlice() {
-               t := temp(f.Type)
+               t := Temp(f.Type)
                as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t))
                as.Lhs.Append(t)
                list = append(list, t)
                n.Results.Set(list)
        }
 
-       n.PtrInit().Append(typecheck(as, ctxStmt))
+       n.PtrInit().Append(Stmt(as))
 }
 
 func checksliceindex(l ir.Node, r ir.Node, tp *types.Type) bool {
        }
        star := ir.NewStarExpr(base.Pos, n)
        star.SetImplicit(true)
-       return typecheck(star, ctxExpr)
+       return Expr(star)
 }
 
 func needOneArg(n *ir.CallExpr, f string, args ...interface{}) (ir.Node, bool) {
                        n.SetType(nil)
                        return n
                }
-               expandmeth(mt)
+               CalcMethods(mt)
                ms = mt.AllMethods()
 
                // The method expression T.m requires a wrapper when T
        }
 
        me := ir.NewMethodExpr(n.Pos(), n.X.Type(), m)
-       me.SetType(methodfunc(m.Type, n.X.Type()))
+       me.SetType(NewMethodType(m.Type, n.X.Type()))
        f := NewName(ir.MethodSym(t, m.Sym))
        f.Class_ = ir.PFUNC
        f.SetType(me.Type())
                        if n.X.Type().IsPtr() {
                                star := ir.NewStarExpr(base.Pos, n.X)
                                star.SetImplicit(true)
-                               n.X = typecheck(star, ctxExpr)
+                               n.X = Expr(star)
                        }
 
                        n.SetOp(ir.ODOTINTER)
                if !types.Identical(rcvr, tt) {
                        if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
                                checklvalue(n.X, "call pointer method on")
-                               addr := nodAddr(n.X)
+                               addr := NodAddr(n.X)
                                addr.SetImplicit(true)
-                               n.X = typecheck(addr, ctxType|ctxExpr)
+                               n.X = check(addr, ctxType|ctxExpr)
                        } else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
                                star := ir.NewStarExpr(base.Pos, n.X)
                                star.SetImplicit(true)
-                               n.X = typecheck(star, ctxType|ctxExpr)
+                               n.X = check(star, ctxType|ctxExpr)
                        } else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
                                base.Errorf("calling method %v with receiver %L requires explicit dereference", n.Sel, n.X)
                                for tt.IsPtr() {
                                        }
                                        star := ir.NewStarExpr(base.Pos, n.X)
                                        star.SetImplicit(true)
-                                       n.X = typecheck(star, ctxType|ctxExpr)
+                                       n.X = check(star, ctxType|ctxExpr)
                                        tt = tt.Elem()
                                }
                        } else {
                // For *T, return &T{...}.
                n.Ntype = ir.TypeNode(t.Elem())
 
-               addr := nodAddrAt(n.Pos(), n)
+               addr := NodAddrAt(n.Pos(), n)
                addr.SetImplicit(true)
                return addr
        }
 
        // Need to handle [...]T arrays specially.
        if array, ok := n.Ntype.(*ir.ArrayType); ok && array.Elem != nil && array.Len == nil {
-               array.Elem = typecheck(array.Elem, ctxType)
+               array.Elem = check(array.Elem, ctxType)
                elemType := array.Elem.Type()
                if elemType == nil {
                        n.SetType(nil)
                return n
        }
 
-       n.Ntype = ir.Node(typecheck(n.Ntype, ctxType)).(ir.Ntype)
+       n.Ntype = ir.Node(check(n.Ntype, ctxType)).(ir.Ntype)
        t := n.Ntype.Type()
        if t == nil {
                n.SetType(nil)
                for i3, l := range n.List {
                        ir.SetPos(l)
                        if l.Op() != ir.OKEY {
-                               n.List[i3] = typecheck(l, ctxExpr)
+                               n.List[i3] = Expr(l)
                                base.Errorf("missing key in map literal")
                                continue
                        }
 
                        r := l.Key
                        r = pushtype(r, t.Key())
-                       r = typecheck(r, ctxExpr)
-                       l.Key = assignconv(r, t.Key(), "map key")
+                       r = Expr(r)
+                       l.Key = AssignConv(r, t.Key(), "map key")
                        cs.add(base.Pos, l.Key, "key", "map literal")
 
                        r = l.Value
                        r = pushtype(r, t.Elem())
-                       r = typecheck(r, ctxExpr)
-                       l.Value = assignconv(r, t.Elem(), "map value")
+                       r = Expr(r)
+                       l.Value = AssignConv(r, t.Elem(), "map value")
                }
 
                n.SetOp(ir.OMAPLIT)
                        ls := n.List
                        for i, n1 := range ls {
                                ir.SetPos(n1)
-                               n1 = typecheck(n1, ctxExpr)
+                               n1 = Expr(n1)
                                ls[i] = n1
                                if i >= t.NumFields() {
                                        if !errored {
                                        base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
                                }
                                // No pushtype allowed here. Must name fields for that.
-                               n1 = assignconv(n1, f.Type, "field value")
+                               n1 = AssignConv(n1, f.Type, "field value")
                                sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1)
                                sk.Offset = f.Offset
                                ls[i] = sk
                                        // package, because of import dot. Redirect to correct sym
                                        // before we do the lookup.
                                        s := key.Sym()
-                                       if id, ok := key.(*ir.Ident); ok && dotImportRefs[id] != nil {
-                                               s = lookup(s.Name)
+                                       if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil {
+                                               s = Lookup(s.Name)
                                        }
 
                                        // An OXDOT uses the Sym field to hold
                                                base.Errorf("mixture of field:value and value initializers")
                                                errored = true
                                        }
-                                       ls[i] = typecheck(ls[i], ctxExpr)
+                                       ls[i] = Expr(ls[i])
                                        continue
                                }
                                l := l.(*ir.StructKeyExpr)
                                l.Offset = f.Offset
 
                                // No pushtype allowed here. Tried and rejected.
-                               l.Value = typecheck(l.Value, ctxExpr)
-                               l.Value = assignconv(l.Value, f.Type, "field value")
+                               l.Value = Expr(l.Value)
+                               l.Value = AssignConv(l.Value, f.Type, "field value")
                        }
                }
 
                var kv *ir.KeyExpr
                if elt.Op() == ir.OKEY {
                        elt := elt.(*ir.KeyExpr)
-                       elt.Key = typecheck(elt.Key, ctxExpr)
-                       key = indexconst(elt.Key)
+                       elt.Key = Expr(elt.Key)
+                       key = IndexConst(elt.Key)
                        if key < 0 {
                                if !elt.Key.Diag() {
                                        if key == -2 {
                }
 
                r = pushtype(r, elemType)
-               r = typecheck(r, ctxExpr)
-               r = assignconv(r, elemType, ctx)
+               r = Expr(r)
+               r = AssignConv(r, elemType, ctx)
                if kv != nil {
                        kv.Value = r
                } else {
        // if the variable has a type (ntype) then typechecking
        // will not look at defn, so it is okay (and desirable,
        // so that the conversion below happens).
-       n.X = resolve(n.X)
+       n.X = Resolve(n.X)
 
        if !ir.DeclaredBy(n.X, n) || n.X.Name().Ntype != nil {
-               n.X = typecheck(n.X, ctxExpr|ctxAssign)
+               n.X = AssignExpr(n.X)
        }
 
        // Use ctxMultiOK so we can emit an "N variables but M values" error
        // to be consistent with typecheckas2 (#26616).
-       n.Y = typecheck(n.Y, ctxExpr|ctxMultiOK)
+       n.Y = check(n.Y, ctxExpr|ctxMultiOK)
        checkassign(n, n.X)
        if n.Y != nil && n.Y.Type() != nil {
                if n.Y.Type().IsFuncArgStruct() {
                        // to indicate failed typechecking.
                        n.Y.SetType(nil)
                } else if n.X.Type() != nil {
-                       n.Y = assignconv(n.Y, n.X.Type(), "assignment")
+                       n.Y = AssignConv(n.Y, n.X.Type(), "assignment")
                }
        }
 
        if ir.DeclaredBy(n.X, n) && n.X.Name().Ntype == nil {
-               n.Y = defaultlit(n.Y, nil)
+               n.Y = DefaultLit(n.Y, nil)
                n.X.SetType(n.Y.Type())
        }
 
        n.SetTypecheck(1)
 
        if n.X.Typecheck() == 0 {
-               n.X = typecheck(n.X, ctxExpr|ctxAssign)
+               n.X = AssignExpr(n.X)
        }
        if !ir.IsBlank(n.X) {
                types.CheckSize(n.X.Type()) // ensure width is calculated for backend
        ls := n.Lhs
        for i1, n1 := range ls {
                // delicate little dance.
-               n1 = resolve(n1)
+               n1 = Resolve(n1)
                ls[i1] = n1
 
                if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil {
-                       ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+                       ls[i1] = AssignExpr(ls[i1])
                }
        }
 
        cl := len(n.Lhs)
        cr := len(n.Rhs)
        if cl > 1 && cr == 1 {
-               n.Rhs[0] = typecheck(n.Rhs[0], ctxExpr|ctxMultiOK)
+               n.Rhs[0] = check(n.Rhs[0], ctxExpr|ctxMultiOK)
        } else {
-               typecheckslice(n.Rhs, ctxExpr)
+               Exprs(n.Rhs)
        }
        checkassignlist(n, n.Lhs)
 
                for il, nl := range ls {
                        nr := rs[il]
                        if nl.Type() != nil && nr.Type() != nil {
-                               rs[il] = assignconv(nr, nl.Type(), "assignment")
+                               rs[il] = AssignConv(nr, nl.Type(), "assignment")
                        }
                        if ir.DeclaredBy(nl, n) && nl.Name().Ntype == nil {
-                               rs[il] = defaultlit(rs[il], nil)
+                               rs[il] = DefaultLit(rs[il], nil)
                                nl.SetType(rs[il].Type())
                        }
                }
        ls = n.Lhs
        for i1, n1 := range ls {
                if n1.Typecheck() == 0 {
-                       ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+                       ls[i1] = AssignExpr(ls[i1])
                }
        }
 }
                }
        }
 
-       n.Nname = typecheck(n.Nname, ctxExpr|ctxAssign).(*ir.Name)
+       n.Nname = AssignExpr(n.Nname).(*ir.Name)
        t := n.Nname.Type()
        if t == nil {
                return
                }
 
                n.Nname.SetSym(ir.MethodSym(rcvr.Type, n.Shortname))
-               declare(n.Nname, ir.PFUNC)
+               Declare(n.Nname, ir.PFUNC)
        }
 
        if base.Ctxt.Flag_dynlink && !inimport && n.Nname != nil {
 
        nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()).(ir.Ntype), nil)
        nn.List.Set(l)
-       return typecheck(nn, ctxExpr)
+       return Expr(nn)
 }
 
 var mapqueue []*ir.MapType
 
-func checkMapKeys() {
+func CheckMapKeys() {
        for _, n := range mapqueue {
                k := n.Type().MapType().Key
                if !k.Broke() && !types.IsComparable(k) {
                        base.ErrorfAt(n.Pos(), "xxx")
                }
 
-               e = typecheck(e, ctxExpr)
+               e = Expr(e)
                if e.Type() == nil {
                        goto ret
                }
                }
 
                if n.Name().Defn.Op() == ir.ONAME {
-                       n.Name().Defn = typecheck(n.Name().Defn, ctxExpr)
+                       n.Name().Defn = Expr(n.Name().Defn)
                        n.SetType(n.Name().Defn.Type())
                        break
                }
 
-               n.Name().Defn = typecheck(n.Name().Defn, ctxStmt) // fills in n.Type
+               n.Name().Defn = Stmt(n.Name().Defn) // fills in n.Type
 
        case ir.OTYPE:
                n := n.(*ir.Name)
        // are the same as for index expressions. Factor the code better;
        // for instance, indexlit might be called here and incorporate some
        // of the bounds checks done for make.
-       n = defaultlit(n, types.Types[types.TINT])
+       n = DefaultLit(n, types.Types[types.TINT])
        *np = n
 
        return true
        return false
 }
 
-// checkreturn makes sure that fn terminates appropriately.
-func checkreturn(fn *ir.Func) {
+// CheckReturn makes sure that fn terminates appropriately.
+func CheckReturn(fn *ir.Func) {
        if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
                markBreak(fn)
                if !isTermNodes(fn.Body) {
        }
        return fnpkg(fn.Nname)
 }
+
+func Conv(n ir.Node, t *types.Type) ir.Node {
+       if types.Identical(n.Type(), t) {
+               return n
+       }
+       n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
+       n.SetType(t)
+       n = Expr(n)
+       return n
+}
+
+// ConvNop converts node n to type t using the OCONVNOP op
+// and typechecks the result with ctxExpr.
+func ConvNop(n ir.Node, t *types.Type) ir.Node {
+       if types.Identical(n.Type(), t) {
+               return n
+       }
+       n = ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
+       n.SetType(t)
+       n = Expr(n)
+       return n
+}
 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(gri) This file should probably become part of package types.
-
-package gc
+package typecheck
 
 import (
+       "go/constant"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
        "cmd/internal/src"
-       "go/constant"
+)
+
+var (
+       okfor [ir.OEND][]bool
+       iscmp [ir.OEND]bool
+)
+
+var (
+       okforeq    [types.NTYPE]bool
+       okforadd   [types.NTYPE]bool
+       okforand   [types.NTYPE]bool
+       okfornone  [types.NTYPE]bool
+       okforbool  [types.NTYPE]bool
+       okforcap   [types.NTYPE]bool
+       okforlen   [types.NTYPE]bool
+       okforarith [types.NTYPE]bool
 )
 
 var basicTypes = [...]struct {
        s = types.BuiltinPkg.Lookup("false")
        s.Def = ir.NewConstAt(src.NoXPos, s, types.UntypedBool, constant.MakeBool(false))
 
-       s = lookup("_")
+       s = Lookup("_")
        types.BlankSym = s
        s.Block = -100
        s.Def = NewName(s)
 
        types.Types[types.TNIL] = types.New(types.TNIL)
        s = types.BuiltinPkg.Lookup("nil")
-       nnil := nodnil()
+       nnil := NodNil()
        nnil.(*ir.NilExpr).SetSym(s)
        s.Def = nnil
 
        sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, []*types.Field{
                types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
        })
-       method := types.NewField(src.NoXPos, lookup("Error"), sig)
+       method := types.NewField(src.NoXPos, Lookup("Error"), sig)
        return types.NewInterface(types.NoPkg, []*types.Field{method})
 }
 
-// finishUniverse makes the universe block visible within the current package.
-func finishUniverse() {
+// declareUniverse makes the universe block visible within the current package.
+func declareUniverse() {
        // Operationally, this is similar to a dot import of builtinpkg, except
        // that we silently skip symbols that are already declared in the
        // package block rather than emitting a redeclared symbol error.
                if s.Def == nil {
                        continue
                }
-               s1 := lookup(s.Name)
+               s1 := Lookup(s.Name)
                if s1.Def != nil {
                        continue
                }
                s1.Block = s.Block
        }
 
-       ir.RegFP = NewName(lookup(".fp"))
+       ir.RegFP = NewName(Lookup(".fp"))
        ir.RegFP.SetType(types.Types[types.TINT32])
        ir.RegFP.Class_ = ir.PPARAM
        ir.RegFP.SetUsed(true)