]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc: manual goto removal + grind to move var decls
authorRuss Cox <rsc@golang.org>
Tue, 3 Mar 2015 01:34:22 +0000 (20:34 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 3 Mar 2015 20:33:57 +0000 (20:33 +0000)
Also change gc.Naddr to return the Addr instead of filling it in.

Change-Id: I98a86705d23bee49626a12a042a4d51cabe290ea
Reviewed-on: https://go-review.googlesource.com/6601
Reviewed-by: Rob Pike <r@golang.org>
16 files changed:
src/cmd/5g/ggen.go
src/cmd/5g/gsubr.go
src/cmd/6g/cgen.go
src/cmd/6g/ggen.go
src/cmd/6g/gsubr.go
src/cmd/6g/peep.go
src/cmd/8g/gsubr.go
src/cmd/9g/ggen.go
src/cmd/9g/gsubr.go
src/cmd/internal/gc/closure.go
src/cmd/internal/gc/dcl.go
src/cmd/internal/gc/gsubr.go
src/cmd/internal/gc/plive.go
src/cmd/internal/gc/range.go
src/cmd/internal/gc/typecheck.go
src/cmd/internal/gc/walk.go

index 374d5e32eed97207ec80a976aef509da3e0056e7..58b0c36b282ec71e29d6c5aea13214c4fde07496 100644 (file)
@@ -78,7 +78,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Pr
                p.Reg = arm.REGSP
                p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
                f := gc.Sysfunc("duffzero")
-               gc.Naddr(f, &p.To, 1)
+               p.To = gc.Naddr(f, 1)
                gc.Afunclit(&p.To, f)
                p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
        } else {
index b8547dd4f180285bbcaaf9d4ab042283c4870951..f2ba6e2bff0e3ace4fa5a3bf6253c72f7aff893d 100644 (file)
@@ -766,12 +766,14 @@ func gmove(f *gc.Node, t *gc.Node) {
        // removed.
        // requires register destination
 rdst:
-       regalloc(&r1, t.Type, t)
+       {
+               regalloc(&r1, t.Type, t)
 
-       gins(a, f, &r1)
-       gmove(&r1, t)
-       regfree(&r1)
-       return
+               gins(a, f, &r1)
+               gmove(&r1, t)
+               regfree(&r1)
+               return
+       }
 
        // requires register intermediate
 hard:
@@ -844,10 +846,10 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 
        var at obj.Addr
        if f != nil {
-               gc.Naddr(f, &af, 1)
+               af = gc.Naddr(f, 1)
        }
        if t != nil {
-               gc.Naddr(t, &at, 1)
+               at = gc.Naddr(t, 1)
        }
        p := gc.Prog(as)
        if f != nil {
@@ -868,7 +870,7 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 func raddr(n *gc.Node, p *obj.Prog) {
        var a obj.Addr
 
-       gc.Naddr(n, &a, 1)
+       a = gc.Naddr(n, 1)
        if a.Type != obj.TYPE_REG {
                if n != nil {
                        gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0))
@@ -1304,7 +1306,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool {
                reg1 := &clean[cleani-2]
                reg.Op = gc.OEMPTY
                reg1.Op = gc.OEMPTY
-               gc.Naddr(n, a, 1)
+               *a = gc.Naddr(n, 1)
                return true
 
        case gc.ODOT,
@@ -1328,7 +1330,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool {
 
                        n1.Type = n.Type
                        n1.Xoffset += oary[0]
-                       gc.Naddr(&n1, a, 1)
+                       *a = gc.Naddr(&n1, 1)
                        return true
                }
 
@@ -1356,7 +1358,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool {
                a.Type = obj.TYPE_NONE
                a.Name = obj.NAME_NONE
                n1.Type = n.Type
-               gc.Naddr(&n1, a, 1)
+               *a = gc.Naddr(&n1, 1)
                return true
 
        case gc.OINDEX:
index 8e282155f6f7fd6a6d5c229cb1e0d4e99db1c70e..0b0d6b32494a343ded4db410f8e325dfcd0f041e 100644 (file)
@@ -1115,8 +1115,6 @@ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
                return
        }
 
-       var nr *gc.Node
-
        for n.Op == gc.OCONVNOP {
                n = n.Left
                if n.Ninit != nil {
@@ -1125,6 +1123,7 @@ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
        }
 
        var nl *gc.Node
+       var nr *gc.Node
        switch n.Op {
        default:
                goto def
index 2934f1e249c348a839127d3fb8b17fb5c2c38773..45242b34a0a57c5ec6ab2deeec98e52451f058f4 100644 (file)
@@ -503,7 +503,6 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
                gmove(&n31, &n3)
        }
 
-       var p2 *obj.Prog
        var n4 gc.Node
        if gc.Nacl {
                // Native Client does not relay the divide-by-zero trap
@@ -520,6 +519,7 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
                gc.Patch(p1, gc.Pc)
        }
 
+       var p2 *obj.Prog
        if check != 0 {
                gc.Nodconst(&n4, t, -1)
                gins(optoas(gc.OCMP, t), &n3, &n4)
index 73afb935014a2cadc9ef71e1c4e8ea2badfdfe28..719a1fee92a736d95523bef8166fc9b5bf8db41e 100644 (file)
@@ -314,7 +314,6 @@ func gmove(f *gc.Node, t *gc.Node) {
        }
 
        // cannot have two memory operands
-       var r1 gc.Node
        var a int
        if gc.Ismem(f) && gc.Ismem(t) {
                goto hard
@@ -669,15 +668,19 @@ func gmove(f *gc.Node, t *gc.Node) {
 
        // requires register destination
 rdst:
-       regalloc(&r1, t.Type, t)
+       {
+               var r1 gc.Node
+               regalloc(&r1, t.Type, t)
 
-       gins(a, f, &r1)
-       gmove(&r1, t)
-       regfree(&r1)
-       return
+               gins(a, f, &r1)
+               gmove(&r1, t)
+               regfree(&r1)
+               return
+       }
 
        // requires register intermediate
 hard:
+       var r1 gc.Node
        regalloc(&r1, cvt, t)
 
        gmove(f, &r1)
@@ -744,12 +747,12 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
        }
 
        var af obj.Addr
-       var at obj.Addr
        if f != nil {
-               gc.Naddr(f, &af, 1)
+               af = gc.Naddr(f, 1)
        }
+       var at obj.Addr
        if t != nil {
-               gc.Naddr(t, &at, 1)
+               at = gc.Naddr(t, 1)
        }
        p := gc.Prog(as)
        if f != nil {
@@ -1402,7 +1405,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
                reg1 := &clean[cleani-2]
                reg.Op = gc.OEMPTY
                reg1.Op = gc.OEMPTY
-               gc.Naddr(n, a, 1)
+               *a = gc.Naddr(n, 1)
                return true
 
        case gc.ODOT,
@@ -1426,7 +1429,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 
                        n1.Type = n.Type
                        n1.Xoffset += oary[0]
-                       gc.Naddr(&n1, a, 1)
+                       *a = gc.Naddr(&n1, 1)
                        return true
                }
 
@@ -1454,7 +1457,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
                a.Type = obj.TYPE_NONE
                a.Index = obj.TYPE_NONE
                fixlargeoffset(&n1)
-               gc.Naddr(&n1, a, 1)
+               *a = gc.Naddr(&n1, 1)
                return true
 
        case gc.OINDEX:
index 7eff5745560740221082e231d486effcb8cc4d9a..a967bba22313f02b73c9336c54c94475996ebb47 100644 (file)
@@ -825,8 +825,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
        if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
                return 0
        }
-       var info gc.ProgInfo
-       info = proginfo(p)
+       info := proginfo(p)
 
        if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 {
                return 2
index 6931ea8732e81726ef5d0483f4baa848b0dfdc62..95ec01aaf67c706a3aacf049f2bb66c59b0af338 100644 (file)
@@ -1148,12 +1148,14 @@ rsrc:
 
        // requires register destination
 rdst:
-       regalloc(&r1, t.Type, t)
+       {
+               regalloc(&r1, t.Type, t)
 
-       gins(a, f, &r1)
-       gmove(&r1, t)
-       regfree(&r1)
-       return
+               gins(a, f, &r1)
+               gmove(&r1, t)
+               regfree(&r1)
+               return
+       }
 
        // requires register intermediate
 hard:
@@ -1845,10 +1847,10 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
        var af obj.Addr
        var at obj.Addr
        if f != nil {
-               gc.Naddr(f, &af, 1)
+               af = gc.Naddr(f, 1)
        }
        if t != nil {
-               gc.Naddr(t, &at, 1)
+               at = gc.Naddr(t, 1)
        }
        p := gc.Prog(as)
        if f != nil {
index 98357eb525b4f7db34932aa364b606a0011bbe8a..d9bcfb70287994e30b12a2a16f6106666e4f0976 100644 (file)
@@ -76,7 +76,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
                p.Reg = ppc64.REGSP
                p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
                f := gc.Sysfunc("duffzero")
-               gc.Naddr(f, &p.To, 1)
+               p.To = gc.Naddr(f, 1)
                gc.Afunclit(&p.To, f)
                p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
        } else {
index 2c51d06dedd11afab8c96286f6a50e397ff2ddbf..1f1a43edb3791342f54efd7b3031b3a79b04fcf2 100644 (file)
@@ -669,12 +669,14 @@ func gmove(f *gc.Node, t *gc.Node) {
 
        // requires register destination
 rdst:
-       regalloc(&r1, t.Type, t)
+       {
+               regalloc(&r1, t.Type, t)
 
-       gins(a, f, &r1)
-       gmove(&r1, t)
-       regfree(&r1)
-       return
+               gins(a, f, &r1)
+               gmove(&r1, t)
+               regfree(&r1)
+               return
+       }
 
        // requires register intermediate
 hard:
@@ -698,10 +700,10 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 
        at := obj.Addr(obj.Addr{})
        if f != nil {
-               gc.Naddr(f, &af, 1)
+               af = gc.Naddr(f, 1)
        }
        if t != nil {
-               gc.Naddr(t, &at, 1)
+               at = gc.Naddr(t, 1)
        }
        p := (*obj.Prog)(gc.Prog(as))
        if f != nil {
index c9b6981aec3881c085f3453abd6f90e5e2d9c1e6..d6f657f1253a404ac5230f299a82aeeeb50b1188 100644 (file)
@@ -596,7 +596,6 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
        declare(xfunc.Nname, PFUNC)
 
        // Declare and initialize variable holding receiver.
-       var body *NodeList
 
        xfunc.Needctxt = true
        cv := Nod(OCLOSUREVAR, nil, nil)
@@ -613,6 +612,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
        ptr.Used = 1
        ptr.Curfn = xfunc
        xfunc.Dcl = list(xfunc.Dcl, ptr)
+       var body *NodeList
        if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
                ptr.Ntype = typenod(rcvrtype)
                body = list(body, Nod(OAS, ptr, cv))
index 8ea5d8dd76d32bf578fe13df4dffba8e33623f1c..a9454e64571c16b8222506ab26007e60c787a9a7 100644 (file)
@@ -313,7 +313,6 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
  * new_name_list [[type] = expr_list]
  */
 func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
-       var vv *NodeList
        if cl == nil {
                if t != nil {
                        Yyerror("const declaration cannot have type without expression")
@@ -329,6 +328,7 @@ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
 
        var v *Node
        var c *Node
+       var vv *NodeList
        for ; vl != nil; vl = vl.Next {
                if cl == nil {
                        Yyerror("missing value in const declaration")
index ad5e494f4fc13c2896ff55f927cc427fa46d0412..48a24a6b56f63fb5a3c92261c477b348377744d1 100644 (file)
@@ -274,8 +274,7 @@ func markautoused(p *obj.Prog) {
        }
 }
 
-func Naddr(n *Node, a *obj.Addr, canemitcode int) {
-       *a = obj.Addr{}
+func Naddr(n *Node, canemitcode int) (a obj.Addr) {
        if n == nil {
                return
        }
@@ -294,7 +293,8 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
 
        switch n.Op {
        default:
-               Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a))
+               a := a // copy to let escape into Ctxt.Dconv
+               Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(&a))
 
        case OREGISTER:
                a.Type = obj.TYPE_REG
@@ -338,7 +338,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
                a.Offset = n.Xoffset
 
        case OCFUNC:
-               Naddr(n.Left, a, canemitcode)
+               a = Naddr(n.Left, canemitcode)
                a.Sym = Linksym(n.Left.Sym)
 
        case ONAME:
@@ -408,7 +408,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
                        a.Offset = Mpgetfix(n.Val.U.Xval)
 
                case CTSTR:
-                       datagostring(n.Val.U.Sval, a)
+                       datagostring(n.Val.U.Sval, &a)
 
                case CTBOOL:
                        a.Sym = nil
@@ -422,19 +422,20 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
                }
 
        case OADDR:
-               Naddr(n.Left, a, canemitcode)
+               a = Naddr(n.Left, canemitcode)
                a.Etype = uint8(Tptr)
                if Thearch.Thechar != '5' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
                        a.Width = int64(Widthptr)
                }
                if a.Type != obj.TYPE_MEM {
-                       Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0))
+                       a := a // copy to let escape into Ctxt.Dconv
+                       Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(&a), Oconv(int(n.Left.Op), 0))
                }
                a.Type = obj.TYPE_ADDR
 
                // itable of interface value
        case OITAB:
-               Naddr(n.Left, a, canemitcode)
+               a = Naddr(n.Left, canemitcode)
 
                if a.Type == obj.TYPE_CONST && a.Offset == 0 {
                        break // itab(nil)
@@ -444,7 +445,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
 
                // pointer in a string or slice
        case OSPTR:
-               Naddr(n.Left, a, canemitcode)
+               a = Naddr(n.Left, canemitcode)
 
                if a.Type == obj.TYPE_CONST && a.Offset == 0 {
                        break // ptr(nil)
@@ -455,7 +456,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
 
                // len of string or slice
        case OLEN:
-               Naddr(n.Left, a, canemitcode)
+               a = Naddr(n.Left, canemitcode)
 
                if a.Type == obj.TYPE_CONST && a.Offset == 0 {
                        break // len(nil)
@@ -471,7 +472,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
 
                // cap of string or slice
        case OCAP:
-               Naddr(n.Left, a, canemitcode)
+               a = Naddr(n.Left, canemitcode)
 
                if a.Type == obj.TYPE_CONST && a.Offset == 0 {
                        break // cap(nil)
@@ -485,6 +486,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) {
                        a.Width = int64(Widthint)
                }
        }
+       return
 }
 
 func newplist() *obj.Plist {
index 545643550962b3a346779558859ff9a5d5fe65d3..ba13cdb1c3df62bcd5fa7124afb081712f0efe7e 100644 (file)
@@ -556,13 +556,11 @@ func isfunny(n *Node) bool {
 // initialized, because any use of a variable must come after its
 // initialization.
 func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avarinit *Bvec) {
-       var info ProgInfo
-
        bvresetall(uevar)
        bvresetall(varkill)
        bvresetall(avarinit)
 
-       info = Thearch.Proginfo(prog)
+       info := Thearch.Proginfo(prog)
        if prog.As == obj.ARET {
                // Return instructions implicitly read all the arguments.  For
                // the sake of correctness, out arguments must be read.  For the
@@ -1087,8 +1085,8 @@ func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog {
        Nodconst(&to, Types[TINT32], int64(index))
        pcdata := unlinkedprog(obj.APCDATA)
        pcdata.Lineno = prog.Lineno
-       Naddr(&from, &pcdata.From, 0)
-       Naddr(&to, &pcdata.To, 0)
+       pcdata.From = Naddr(&from, 0)
+       pcdata.To = Naddr(&to, 0)
        return pcdata
 }
 
@@ -1296,7 +1294,6 @@ func livenessepilogue(lv *Liveness) {
        any := bvalloc(nvars)
        all := bvalloc(nvars)
        ambig := bvalloc(localswords() * obj.BitsPerPointer)
-       var msg []string
        nmsg := int32(0)
        startmsg := int32(0)
 
@@ -1392,6 +1389,7 @@ func livenessepilogue(lv *Liveness) {
        var fmt_ string
        var next *obj.Prog
        var numlive int32
+       var msg []string
        for i := int32(0); i < int32(len(lv.cfg)); i++ {
                bb = lv.cfg[i]
 
index ed50bdf67ea1ad44fbf68f97e7d5fd7f98d830f5..3de70ba71c7a4232434563ed7af497deb0b572eb 100644 (file)
@@ -136,7 +136,6 @@ out:
 
 func walkrange(n *Node) {
        t := n.Type
-       var init *NodeList
 
        a := n.Right
        lno := int(setlineno(a))
@@ -154,9 +153,8 @@ func walkrange(n *Node) {
        // to avoid erroneous processing by racewalk.
        n.List = nil
 
-       var hv2 *Node
-
        var body *NodeList
+       var init *NodeList
        switch t.Etype {
        default:
                Fatal("walkrange")
@@ -366,6 +364,7 @@ func walkrange(n *Node) {
                init = list(init, Nod(OAS, hv1, nil))
 
                var a *Node
+               var hv2 *Node
                if v2 == nil {
                        a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1))
                } else {
index 0ff8224e629fb86f3eba51085c57c4cc811dd339..845aac6965da12f71421152e6a3c6b790d8478cd 100644 (file)
@@ -276,44 +276,27 @@ func indexlit(np **Node) {
 }
 
 func typecheck1(np **Node, top int) {
-       var et int
-       var aop int
-       var op int
-       var ptr int
-       var l *Node
-       var r *Node
-       var lo *Node
-       var mid *Node
-       var hi *Node
-       var ok int
-       var ntop int
-       var t *Type
-       var tp *Type
-       var missing *Type
-       var have *Type
-       var badtype *Type
-       var v Val
-       var why string
-       var x int64
-
        n := *np
+       defer func() {
+               *np = n
+       }()
 
        if n.Sym != nil {
                if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
                        Yyerror("use of builtin %v not in function call", Sconv(n.Sym, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                typecheckdef(n)
                if n.Op == ONONAME {
-                       goto error
+                       n.Type = nil
+                       return
                }
        }
 
-       *np = n
-
-reswitch:
-       ok = 0
+       ok := 0
+OpSwitch:
        switch n.Op {
        // until typecheck is complete, do nothing.
        default:
@@ -330,11 +313,11 @@ reswitch:
                if n.Type == nil && n.Val.Ctype == CTSTR {
                        n.Type = idealstring
                }
-               goto ret
+               break OpSwitch
 
        case ONONAME:
                ok |= Erv
-               goto ret
+               break OpSwitch
 
        case ONAME:
                if n.Decldepth == 0 {
@@ -342,14 +325,15 @@ reswitch:
                }
                if n.Etype != 0 {
                        ok |= Ecall
-                       goto ret
+                       break OpSwitch
                }
 
                if top&Easgn == 0 {
                        // not a write to the variable
                        if isblank(n) {
                                Yyerror("cannot use _ as value")
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        n.Used = 1
@@ -357,15 +341,17 @@ reswitch:
 
                if top&Ecall == 0 && isunsafebuiltin(n) {
                        Yyerror("%v is not an expression, must be called", Nconv(n, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                ok |= Erv
-               goto ret
+               break OpSwitch
 
        case OPACK:
                Yyerror("use of package %v without selector", Sconv(n.Sym, 0))
-               goto error
+               n.Type = nil
+               return
 
        case ODDD:
                break
@@ -377,14 +363,15 @@ reswitch:
                ok |= Etype
 
                if n.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
 
        case OTARRAY:
                ok |= Etype
-               t = typ(TARRAY)
-               l = n.Left
-               r = n.Right
+               t := typ(TARRAY)
+               l := n.Left
+               r := n.Right
                if l == nil {
                        t.Bound = -1 // slice
                } else if l.Op == ODDD {
@@ -395,7 +382,8 @@ reswitch:
                                Yyerror("use of [...] array outside of array literal")
                        }
                } else {
-                       l = typecheck(&n.Left, Erv)
+                       l := typecheck(&n.Left, Erv)
+                       var v Val
                        switch consttype(l) {
                        case CTINT,
                                CTRUNE:
@@ -410,22 +398,26 @@ reswitch:
                                } else {
                                        Yyerror("invalid array bound %v", Nconv(l, 0))
                                }
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        t.Bound = Mpgetfix(v.U.Xval)
                        if doesoverflow(v, Types[TINT]) {
                                Yyerror("array bound is too large")
-                               goto error
+                               n.Type = nil
+                               return
                        } else if t.Bound < 0 {
                                Yyerror("array bound must be non-negative")
-                               goto error
+                               n.Type = nil
+                               return
                        }
                }
 
                typecheck(&r, Etype)
                if r.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                t.Type = r.Type
                n.Op = OTYPE
@@ -438,10 +430,11 @@ reswitch:
 
        case OTMAP:
                ok |= Etype
-               l = typecheck(&n.Left, Etype)
-               r = typecheck(&n.Right, Etype)
+               l := typecheck(&n.Left, Etype)
+               r := typecheck(&n.Right, Etype)
                if l.Type == nil || r.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                n.Op = OTYPE
                n.Type = maptype(l.Type, r.Type)
@@ -450,11 +443,12 @@ reswitch:
 
        case OTCHAN:
                ok |= Etype
-               l = typecheck(&n.Left, Etype)
+               l := typecheck(&n.Left, Etype)
                if l.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               t = typ(TCHAN)
+               t := typ(TCHAN)
                t.Type = l.Type
                t.Chan = n.Etype
                n.Op = OTYPE
@@ -467,7 +461,8 @@ reswitch:
                n.Op = OTYPE
                n.Type = tostruct(n.List)
                if n.Type == nil || n.Type.Broke != 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
                n.List = nil
 
@@ -476,7 +471,8 @@ reswitch:
                n.Op = OTYPE
                n.Type = tointerface(n.List)
                if n.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
 
        case OTFUNC:
@@ -484,61 +480,53 @@ reswitch:
                n.Op = OTYPE
                n.Type = functype(n.Left, n.List, n.Rlist)
                if n.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                /*
                 * type or expr
                 */
        case OIND:
-               ntop = Erv | Etype
+               ntop := Erv | Etype
 
                if top&Eaddr == 0 {
                        ntop |= Eindir
                }
                ntop |= top & Ecomplit
-               l = typecheck(&n.Left, ntop)
-               t = l.Type
+               l := typecheck(&n.Left, ntop)
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if l.Op == OTYPE {
                        ok |= Etype
                        n.Op = OTYPE
                        n.Type = Ptrto(l.Type)
                        n.Left = nil
-                       goto ret
+                       break OpSwitch
                }
 
                if !Isptr[t.Etype] {
                        if top&(Erv|Etop) != 0 {
                                Yyerror("invalid indirect of %v", Nconv(n.Left, obj.FmtLong))
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
-                       goto ret
+                       break OpSwitch
                }
 
                ok |= Erv
                n.Type = t.Type
-               goto ret
+               break OpSwitch
 
                /*
                 * arithmetic exprs
                 */
-       case OASOP:
-               ok |= Etop
-
-               l = typecheck(&n.Left, Erv)
-               r = typecheck(&n.Right, Erv)
-               checkassign(n, n.Left)
-               if l.Type == nil || r.Type == nil {
-                       goto error
-               }
-               op = int(n.Etype)
-               goto arith
-
-       case OADD,
+       case OASOP,
+               OADD,
                OAND,
                OANDAND,
                OANDNOT,
@@ -557,32 +545,270 @@ reswitch:
                OOROR,
                OSUB,
                OXOR:
-               ok |= Erv
-               l = typecheck(&n.Left, Erv|top&Eiota)
-               r = typecheck(&n.Right, Erv|top&Eiota)
+               var l *Node
+               var op int
+               var r *Node
+               if n.Op == OASOP {
+                       ok |= Etop
+                       l = typecheck(&n.Left, Erv)
+                       r = typecheck(&n.Right, Erv)
+                       checkassign(n, n.Left)
+                       if l.Type == nil || r.Type == nil {
+                               n.Type = nil
+                               return
+                       }
+                       op = int(n.Etype)
+               } else {
+                       ok |= Erv
+                       l = typecheck(&n.Left, Erv|top&Eiota)
+                       r = typecheck(&n.Right, Erv|top&Eiota)
+                       if l.Type == nil || r.Type == nil {
+                               n.Type = nil
+                               return
+                       }
+                       op = int(n.Op)
+               }
+               if op == OLSH || op == ORSH {
+                       defaultlit(&r, Types[TUINT])
+                       n.Right = r
+                       t := r.Type
+                       if !Isint[t.Etype] || Issigned[t.Etype] {
+                               Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0))
+                               n.Type = nil
+                               return
+                       }
+
+                       t = l.Type
+                       if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] {
+                               Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
+                               n.Type = nil
+                               return
+                       }
+
+                       // no defaultlit for left
+                       // the outer context gives the type
+                       n.Type = l.Type
+
+                       break OpSwitch
+               }
+
+               // ideal mixed with non-ideal
+               defaultlit2(&l, &r, 0)
+
+               n.Left = l
+               n.Right = r
                if l.Type == nil || r.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
+               }
+               t := l.Type
+               if t.Etype == TIDEAL {
+                       t = r.Type
+               }
+               et := int(t.Etype)
+               if et == TIDEAL {
+                       et = TINT
+               }
+               aop := 0
+               if iscmp[n.Op] && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
+                       // comparison is okay as long as one side is
+                       // assignable to the other.  convert so they have
+                       // the same type.
+                       //
+                       // the only conversion that isn't a no-op is concrete == interface.
+                       // in that case, check comparability of the concrete type.
+                       // The conversion allocates, so only do it if the concrete type is huge.
+                       if r.Type.Etype != TBLANK {
+                               aop = assignop(l.Type, r.Type, nil)
+                               if aop != 0 {
+                                       if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ {
+                                               Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type))
+                                               n.Type = nil
+                                               return
+                                       }
+
+                                       dowidth(l.Type)
+                                       if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 {
+                                               l = Nod(aop, l, nil)
+                                               l.Type = r.Type
+                                               l.Typecheck = 1
+                                               n.Left = l
+                                       }
+
+                                       t = r.Type
+                                       goto converted
+                               }
+                       }
+
+                       if l.Type.Etype != TBLANK {
+                               aop = assignop(r.Type, l.Type, nil)
+                               if aop != 0 {
+                                       if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ {
+                                               Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type))
+                                               n.Type = nil
+                                               return
+                                       }
+
+                                       dowidth(r.Type)
+                                       if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 {
+                                               r = Nod(aop, r, nil)
+                                               r.Type = l.Type
+                                               r.Typecheck = 1
+                                               n.Right = r
+                                       }
+
+                                       t = l.Type
+                               }
+                       }
+
+               converted:
+                       et = int(t.Etype)
+               }
+
+               if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
+                       defaultlit2(&l, &r, 1)
+                       if n.Op == OASOP && n.Implicit != 0 {
+                               Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0))
+                               n.Type = nil
+                               return
+                       }
+
+                       if Isinter(r.Type) == Isinter(l.Type) || aop == 0 {
+                               Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
+                               n.Type = nil
+                               return
+                       }
+               }
+
+               if !okfor[op][et] {
+                       Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t))
+                       n.Type = nil
+                       return
+               }
+
+               // okfor allows any array == array, map == map, func == func.
+               // restrict to slice/map/func == nil and nil == slice/map/func.
+               if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ {
+                       Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0))
+                       n.Type = nil
+                       return
+               }
+
+               if Isslice(l.Type) && !isnil(l) && !isnil(r) {
+                       Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0))
+                       n.Type = nil
+                       return
+               }
+
+               if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
+                       Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0))
+                       n.Type = nil
+                       return
+               }
+
+               if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
+                       Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0))
+                       n.Type = nil
+                       return
+               }
+
+               var badtype *Type
+               if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ {
+                       Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0))
+                       n.Type = nil
+                       return
+               }
+
+               t = l.Type
+               if iscmp[n.Op] {
+                       evconst(n)
+                       t = idealbool
+                       if n.Op != OLITERAL {
+                               defaultlit2(&l, &r, 1)
+                               n.Left = l
+                               n.Right = r
+                       }
+               } else if n.Op == OANDAND || n.Op == OOROR {
+                       if l.Type == r.Type {
+                               t = l.Type
+                       } else if l.Type == idealbool {
+                               t = r.Type
+                       } else if r.Type == idealbool {
+                               t = l.Type
+                       }
+               } else
+               // non-comparison operators on ideal bools should make them lose their ideal-ness
+               if t == idealbool {
+                       t = Types[TBOOL]
+               }
+
+               if et == TSTRING {
+                       if iscmp[n.Op] {
+                               n.Etype = n.Op
+                               n.Op = OCMPSTR
+                       } else if n.Op == OADD {
+                               // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
+                               n.Op = OADDSTR
+
+                               if l.Op == OADDSTR {
+                                       n.List = l.List
+                               } else {
+                                       n.List = list1(l)
+                               }
+                               if r.Op == OADDSTR {
+                                       n.List = concat(n.List, r.List)
+                               } else {
+                                       n.List = list(n.List, r)
+                               }
+                               n.Left = nil
+                               n.Right = nil
+                       }
+               }
+
+               if et == TINTER {
+                       if l.Op == OLITERAL && l.Val.Ctype == CTNIL {
+                               // swap for back end
+                               n.Left = r
+
+                               n.Right = l
+                       } else if r.Op == OLITERAL && r.Val.Ctype == CTNIL {
+                       } else // leave alone for back end
+                       if Isinter(r.Type) == Isinter(l.Type) {
+                               n.Etype = n.Op
+                               n.Op = OCMPIFACE
+                       }
                }
-               op = int(n.Op)
-               goto arith
+
+               if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
+                       if mpcmpfixc(r.Val.U.Xval, 0) == 0 {
+                               Yyerror("division by zero")
+                               n.Type = nil
+                               return
+                       }
+               }
+
+               n.Type = t
+               break OpSwitch
 
        case OCOM,
                OMINUS,
                ONOT,
                OPLUS:
                ok |= Erv
-               l = typecheck(&n.Left, Erv|top&Eiota)
-               t = l.Type
+               l := typecheck(&n.Left, Erv|top&Eiota)
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if !okfor[n.Op][t.Etype] {
                        Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.Type = t
-               goto ret
+               break OpSwitch
 
                /*
                 * exprs
@@ -592,10 +818,12 @@ reswitch:
 
                typecheck(&n.Left, Erv|Eaddr)
                if n.Left.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                checklvalue(n.Left, "take the address of")
-               r = outervalue(n.Left)
+               r := outervalue(n.Left)
+               var l *Node
                for l = n.Left; l != r; l = l.Left {
                        l.Addrtaken = 1
                        if l.Closure != nil {
@@ -612,46 +840,50 @@ reswitch:
                }
                defaultlit(&n.Left, nil)
                l = n.Left
-               t = l.Type
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                n.Type = Ptrto(t)
-               goto ret
+               break OpSwitch
 
        case OCOMPLIT:
                ok |= Erv
                typecheckcomplit(&n)
                if n.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               goto ret
+               break OpSwitch
 
-       case OXDOT:
-               n = adddot(n)
-               n.Op = ODOT
-               if n.Left == nil {
-                       goto error
+       case OXDOT, ODOT:
+               if n.Op == OXDOT {
+                       n = adddot(n)
+                       n.Op = ODOT
+                       if n.Left == nil {
+                               n.Type = nil
+                               return
+                       }
                }
-               fallthrough
 
-               // fall through
-       case ODOT:
                typecheck(&n.Left, Erv|Etype)
 
                defaultlit(&n.Left, nil)
                if n.Right.Op != ONAME {
                        Yyerror("rhs of . must be a name") // impossible
-                       goto error
+                       n.Type = nil
+                       return
                }
 
-               t = n.Left.Type
+               t := n.Left.Type
                if t == nil {
                        adderrorname(n)
-                       goto error
+                       n.Type = nil
+                       return
                }
 
-               r = n.Right
+               r := n.Right
 
                if n.Left.Op == OTYPE {
                        if !looktypedot(n, t, 0) {
@@ -660,13 +892,15 @@ reswitch:
                                } else {
                                        Yyerror("%v undefined (type %v has no method %v)", Nconv(n, 0), Tconv(t, 0), Sconv(n.Right.Sym, 0))
                                }
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        if n.Type.Etype != TFUNC || n.Type.Thistuple != 1 {
                                Yyerror("type %v has no method %v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort))
                                n.Type = nil
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        n.Op = ONAME
@@ -675,13 +909,14 @@ reswitch:
                        n.Xoffset = 0
                        n.Class = PFUNC
                        ok = Erv
-                       goto ret
+                       break OpSwitch
                }
 
                if Isptr[t.Etype] && t.Type.Etype != TINTER {
                        t = t.Type
                        if t == nil {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        n.Op = ODOTPTR
                        checkwidth(t)
@@ -689,7 +924,8 @@ reswitch:
 
                if isblank(n.Right) {
                        Yyerror("cannot refer to blank field or method")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if !lookdot(n, t, 0) {
@@ -698,7 +934,8 @@ reswitch:
                        } else {
                                Yyerror("%v undefined (type %v has no field or method %v)", Nconv(n, 0), Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
                        }
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                switch n.Op {
@@ -715,20 +952,22 @@ reswitch:
                        ok |= Erv
                }
 
-               goto ret
+               break OpSwitch
 
        case ODOTTYPE:
                ok |= Erv
                typecheck(&n.Left, Erv)
                defaultlit(&n.Left, nil)
-               l = n.Left
-               t = l.Type
+               l := n.Left
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if !Isinter(t) {
                        Yyerror("invalid type assertion: %v (non-interface type %v on left)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if n.Right != nil {
@@ -736,11 +975,15 @@ reswitch:
                        n.Type = n.Right.Type
                        n.Right = nil
                        if n.Type == nil {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                }
 
                if n.Type != nil && n.Type.Etype != TINTER {
+                       var have *Type
+                       var missing *Type
+                       var ptr int
                        if !implements(n.Type, t, &missing, &have, &ptr) {
                                if have != nil && have.Sym == missing.Sym {
                                        Yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
@@ -751,28 +994,31 @@ reswitch:
                                } else {
                                        Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0))
                                }
-                               goto error
+                               n.Type = nil
+                               return
                        }
                }
 
-               goto ret
+               break OpSwitch
 
        case OINDEX:
                ok |= Erv
                typecheck(&n.Left, Erv)
                defaultlit(&n.Left, nil)
                implicitstar(&n.Left)
-               l = n.Left
+               l := n.Left
                typecheck(&n.Right, Erv)
-               r = n.Right
-               t = l.Type
+               r := n.Right
+               t := l.Type
                if t == nil || r.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                switch t.Etype {
                default:
                        Yyerror("invalid operation: %v (type %v does not support indexing)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
 
                case TSTRING,
                        TARRAY:
@@ -782,7 +1028,7 @@ reswitch:
                        } else {
                                n.Type = t.Type
                        }
-                       why = "string"
+                       why := "string"
                        if t.Etype == TARRAY {
                                if Isfixedarray(t) {
                                        why = "array"
@@ -797,7 +1043,7 @@ reswitch:
                        }
 
                        if Isconst(n.Right, CTINT) {
-                               x = Mpgetfix(n.Right.Val.U.Xval)
+                               x := Mpgetfix(n.Right.Val.U.Xval)
                                if x < 0 {
                                        Yyerror("invalid %s index %v (index must be non-negative)", why, Nconv(n.Right, 0))
                                } else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound {
@@ -819,54 +1065,61 @@ reswitch:
                        n.Op = OINDEXMAP
                }
 
-               goto ret
+               break OpSwitch
 
        case ORECV:
                ok |= Etop | Erv
                typecheck(&n.Left, Erv)
                defaultlit(&n.Left, nil)
-               l = n.Left
-               t = l.Type
+               l := n.Left
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if t.Etype != TCHAN {
                        Yyerror("invalid operation: %v (receive from non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if t.Chan&Crecv == 0 {
                        Yyerror("invalid operation: %v (receive from send-only type %v)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.Type = t.Type
-               goto ret
+               break OpSwitch
 
        case OSEND:
                ok |= Etop
-               l = typecheck(&n.Left, Erv)
+               l := typecheck(&n.Left, Erv)
                typecheck(&n.Right, Erv)
                defaultlit(&n.Left, nil)
                l = n.Left
-               t = l.Type
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if t.Etype != TCHAN {
                        Yyerror("invalid operation: %v (send to non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if t.Chan&Csend == 0 {
                        Yyerror("invalid operation: %v (send to receive-only type %v)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                defaultlit(&n.Right, t.Type)
-               r = n.Right
+               r := n.Right
                if r.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                n.Right = assignconv(r, l.Type.Type, "send")
 
@@ -874,7 +1127,7 @@ reswitch:
                n.Etype = 0
 
                n.Type = nil
-               goto ret
+               break OpSwitch
 
        case OSLICE:
                ok |= Erv
@@ -884,11 +1137,12 @@ reswitch:
                defaultlit(&n.Left, nil)
                indexlit(&n.Right.Left)
                indexlit(&n.Right.Right)
-               l = n.Left
+               l := n.Left
                if Isfixedarray(l.Type) {
                        if !islvalue(n.Left) {
                                Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0))
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        n.Left = Nod(OADDR, n.Left, nil)
@@ -897,11 +1151,12 @@ reswitch:
                        l = n.Left
                }
 
-               t = l.Type
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               tp = nil
+               var tp *Type
                if Istype(t, TSTRING) {
                        n.Type = t
                        n.Op = OSLICESTR
@@ -916,21 +1171,25 @@ reswitch:
                        n.Type = t
                } else {
                        Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
-               lo = n.Right.Left
+               lo := n.Right.Left
                if lo != nil && checksliceindex(l, lo, tp) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               hi = n.Right.Right
+               hi := n.Right.Right
                if hi != nil && checksliceindex(l, hi, tp) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if checksliceconst(lo, hi) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               goto ret
+               break OpSwitch
 
        case OSLICE3:
                ok |= Erv
@@ -942,11 +1201,12 @@ reswitch:
                indexlit(&n.Right.Left)
                indexlit(&n.Right.Right.Left)
                indexlit(&n.Right.Right.Right)
-               l = n.Left
+               l := n.Left
                if Isfixedarray(l.Type) {
                        if !islvalue(n.Left) {
                                Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0))
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        n.Left = Nod(OADDR, n.Left, nil)
@@ -955,16 +1215,18 @@ reswitch:
                        l = n.Left
                }
 
-               t = l.Type
+               t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               tp = nil
                if Istype(t, TSTRING) {
                        Yyerror("invalid operation %v (3-index slice of string)", Nconv(n, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
+               var tp *Type
                if Isptr[t.Etype] && Isfixedarray(t.Type) {
                        tp = t.Type
                        n.Type = typ(TARRAY)
@@ -976,40 +1238,46 @@ reswitch:
                        n.Type = t
                } else {
                        Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
-               lo = n.Right.Left
+               lo := n.Right.Left
                if lo != nil && checksliceindex(l, lo, tp) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               mid = n.Right.Right.Left
+               mid := n.Right.Right.Left
                if mid != nil && checksliceindex(l, mid, tp) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               hi = n.Right.Right.Right
+               hi := n.Right.Right.Right
                if hi != nil && checksliceindex(l, hi, tp) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               goto ret
+               break OpSwitch
 
                /*
                 * call and call like
                 */
        case OCALL:
-               l = n.Left
+               l := n.Left
 
                if l.Op == ONAME {
-                       r = unsafenmagic(n)
+                       r := unsafenmagic(n)
                        if r != nil {
                                if n.Isddd != 0 {
                                        Yyerror("invalid use of ... with builtin %v", Nconv(l, 0))
                                }
                                n = r
-                               goto reswitch
+                               typecheck1(&n, top)
+                               return
                        }
                }
 
@@ -1026,11 +1294,12 @@ reswitch:
 
                        n.Left = n.Right
                        n.Right = nil
-                       goto reswitch
+                       typecheck1(&n, top)
+                       return
                }
 
                defaultlit(&n.Left, nil)
-               l := n.Left
+               l = n.Left
                if l.Op == OTYPE {
                        if n.Isddd != 0 || l.Type.Bound == -100 {
                                if l.Type.Broke == 0 {
@@ -1048,9 +1317,11 @@ reswitch:
                        n.Op = OCONV
                        n.Type = l.Type
                        if onearg(n, "conversion to %v", Tconv(l.Type, 0)) < 0 {
-                               goto error
+                               n.Type = nil
+                               return
                        }
-                       goto doconv
+                       typecheck1(&n, top)
+                       return
                }
 
                if count(n.List) == 1 && n.Isddd == 0 {
@@ -1060,7 +1331,8 @@ reswitch:
                }
                t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                checkwidth(t)
 
@@ -1085,7 +1357,8 @@ reswitch:
                        n.Op = OCALLFUNC
                        if t.Etype != TFUNC {
                                Yyerror("cannot call non-function %v (type %v)", Nconv(l, 0), Tconv(t, 0))
-                               goto error
+                               n.Type = nil
+                               return
                        }
                }
 
@@ -1094,29 +1367,30 @@ reswitch:
                typecheckaste(OCALL, n.Left, int(n.Isddd), getinargx(t), n.List, desc)
                ok |= Etop
                if t.Outtuple == 0 {
-                       goto ret
+                       break OpSwitch
                }
                ok |= Erv
                if t.Outtuple == 1 {
                        t := getoutargx(l.Type).Type
                        if t == nil {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        if t.Etype == TFIELD {
                                t = t.Type
                        }
                        n.Type = t
-                       goto ret
+                       break OpSwitch
                }
 
                // multiple return
                if top&(Efnstruct|Etop) == 0 {
                        Yyerror("multiple-value %v() in single-value context", Nconv(l, 0))
-                       goto ret
+                       break OpSwitch
                }
 
                n.Type = getoutargx(l.Type)
-               goto ret
+               break OpSwitch
 
        case OCAP,
                OLEN,
@@ -1124,7 +1398,8 @@ reswitch:
                OIMAG:
                ok |= Erv
                if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
                typecheck(&n.Left, Erv)
                defaultlit(&n.Left, nil)
@@ -1132,7 +1407,8 @@ reswitch:
                l := n.Left
                t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                switch n.Op {
                case OCAP:
@@ -1161,7 +1437,7 @@ reswitch:
                        }
 
                        n.Type = Types[cplxsubtype(int(t.Etype))]
-                       goto ret
+                       break OpSwitch
                }
 
                // might be constant
@@ -1188,7 +1464,12 @@ reswitch:
                }
 
                n.Type = Types[TINT]
-               goto ret
+               break OpSwitch
+
+       badcall1:
+               Yyerror("invalid argument %v for %v", Nconv(n.Left, obj.FmtLong), Oconv(int(n.Op), 0))
+               n.Type = nil
+               return
 
        case OCOMPLEX:
                ok |= Erv
@@ -1198,13 +1479,15 @@ reswitch:
                        typechecklist(n.List, Efnstruct)
                        if n.List.N.Op != OCALLFUNC && n.List.N.Op != OCALLMETH {
                                Yyerror("invalid operation: complex expects two arguments")
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        t := n.List.N.Left.Type
                        if t.Outtuple != 2 {
                                Yyerror("invalid operation: complex expects two arguments, %v returns %d results", Nconv(n.List.N, 0), t.Outtuple)
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        t = n.List.N.Type.Type
@@ -1212,16 +1495,19 @@ reswitch:
                        r = t.Down.Nname
                } else {
                        if twoarg(n) < 0 {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        l = typecheck(&n.Left, Erv|top&Eiota)
                        r = typecheck(&n.Right, Erv|top&Eiota)
                        if l.Type == nil || r.Type == nil {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        defaultlit2(&l, &r, 0)
                        if l.Type == nil || r.Type == nil {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        n.Left = l
                        n.Right = r
@@ -1229,14 +1515,16 @@ reswitch:
 
                if !Eqtype(l.Type, r.Type) {
                        Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                var t *Type
                switch l.Type.Etype {
                default:
                        Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", Nconv(n, 0), Tconv(l.Type, 0), r.Type)
-                       goto error
+                       n.Type = nil
+                       return
 
                case TIDEAL:
                        t = Types[TIDEAL]
@@ -1257,47 +1545,54 @@ reswitch:
                }
 
                n.Type = t
-               goto ret
+               break OpSwitch
 
        case OCLOSE:
                if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
                typecheck(&n.Left, Erv)
                defaultlit(&n.Left, nil)
                l := n.Left
                t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if t.Etype != TCHAN {
                        Yyerror("invalid operation: %v (non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if t.Chan&Csend == 0 {
                        Yyerror("invalid operation: %v (cannot close receive-only channel)", Nconv(n, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                ok |= Etop
-               goto ret
+               break OpSwitch
 
        case ODELETE:
                args := n.List
                if args == nil {
                        Yyerror("missing arguments to delete")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if args.Next == nil {
                        Yyerror("missing second (key) argument to delete")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if args.Next.Next != nil {
                        Yyerror("too many arguments to delete")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                ok |= Etop
@@ -1306,18 +1601,20 @@ reswitch:
                r := args.Next.N
                if l.Type != nil && l.Type.Etype != TMAP {
                        Yyerror("first argument to delete must be map; have %v", Tconv(l.Type, obj.FmtLong))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                args.Next.N = assignconv(r, l.Type.Down, "delete")
-               goto ret
+               break OpSwitch
 
        case OAPPEND:
                ok |= Erv
                args := n.List
                if args == nil {
                        Yyerror("missing arguments to append")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if count(args) == 1 && n.Isddd == 0 {
@@ -1328,7 +1625,8 @@ reswitch:
 
                t := args.N.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                // Unpack multiple-return result before type-checking.
@@ -1343,31 +1641,35 @@ reswitch:
                if !Isslice(t) {
                        if Isconst(args.N, CTNIL) {
                                Yyerror("first argument to append must be typed slice; have untyped nil", t)
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        Yyerror("first argument to append must be slice; have %v", Tconv(t, obj.FmtLong))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if n.Isddd != 0 {
                        if args.Next == nil {
                                Yyerror("cannot use ... on first argument to append")
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        if args.Next.Next != nil {
                                Yyerror("too many arguments to append")
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        if Istype(t.Type, TUINT8) && Istype(args.Next.N.Type, TSTRING) {
                                defaultlit(&args.Next.N, Types[TSTRING])
-                               goto ret
+                               break OpSwitch
                        }
 
                        args.Next.N = assignconv(args.Next.N, t.Orig, "append")
-                       goto ret
+                       break OpSwitch
                }
 
                for args = args.Next; args != nil; args = args.Next {
@@ -1377,19 +1679,21 @@ reswitch:
                        args.N = assignconv(args.N, t.Type, "append")
                }
 
-               goto ret
+               break OpSwitch
 
        case OCOPY:
                ok |= Etop | Erv
                args := n.List
                if args == nil || args.Next == nil {
                        Yyerror("missing arguments to copy")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if args.Next.Next != nil {
                        Yyerror("too many arguments to copy")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.Left = args.N
@@ -1399,21 +1703,24 @@ reswitch:
                typecheck(&n.Left, Erv)
                typecheck(&n.Right, Erv)
                if n.Left.Type == nil || n.Right.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                defaultlit(&n.Left, nil)
                defaultlit(&n.Right, nil)
                if n.Left.Type == nil || n.Right.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                // copy([]byte, string)
                if Isslice(n.Left.Type) && n.Right.Type.Etype == TSTRING {
                        if Eqtype(n.Left.Type.Type, bytetype) {
-                               goto ret
+                               break OpSwitch
                        }
                        Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, obj.FmtLong))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if !Isslice(n.Left.Type) || !Isslice(n.Right.Type) {
@@ -1424,25 +1731,73 @@ reswitch:
                        } else {
                                Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, obj.FmtLong))
                        }
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if !Eqtype(n.Left.Type.Type, n.Right.Type.Type) {
                        Yyerror("arguments to copy have different element types: %v and %v", Tconv(n.Left.Type, obj.FmtLong), Tconv(n.Right.Type, obj.FmtLong))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
-               goto ret
+               break OpSwitch
 
        case OCONV:
-               goto doconv
+               {
+                       ok |= Erv
+                       saveorignode(n)
+                       typecheck(&n.Left, Erv|top&(Eindir|Eiota))
+                       convlit1(&n.Left, n.Type, true)
+                       t := n.Left.Type
+                       if t == nil || n.Type == nil {
+                               n.Type = nil
+                               return
+                       }
+                       var why string
+                       n.Op = uint8(convertop(t, n.Type, &why))
+                       if (n.Op) == 0 {
+                               if n.Diag == 0 && n.Type.Broke == 0 {
+                                       Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why)
+                                       n.Diag = 1
+                               }
+
+                               n.Op = OCONV
+                       }
+
+                       switch n.Op {
+                       case OCONVNOP:
+                               if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] {
+                                       r := Nod(OXXX, nil, nil)
+                                       n.Op = OCONV
+                                       n.Orig = r
+                                       *r = *n
+                                       n.Op = OLITERAL
+                                       n.Val = n.Left.Val
+                               }
+
+                               // do not use stringtoarraylit.
+                       // generated code and compiler memory footprint is better without it.
+                       case OSTRARRAYBYTE:
+                               break
+
+                       case OSTRARRAYRUNE:
+                               if n.Left.Op == OLITERAL {
+                                       stringtoarraylit(&n)
+                               }
+                       }
+
+                       break OpSwitch
+               }
+               break OpSwitch
 
        case OMAKE:
                ok |= Erv
                args := n.List
                if args == nil {
                        Yyerror("missing argument to make")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.List = nil
@@ -1451,23 +1806,27 @@ reswitch:
                typecheck(&l, Etype)
                t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                switch t.Etype {
                default:
                        Yyerror("cannot make type %v", Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
 
                case TARRAY:
                        if !Isslice(t) {
                                Yyerror("cannot make type %v", Tconv(t, 0))
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        if args == nil {
                                Yyerror("missing len argument to make(%v)", Tconv(t, 0))
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        l = args.N
@@ -1481,16 +1840,19 @@ reswitch:
                        }
 
                        if l.Type == nil || (r != nil && r.Type == nil) {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        et := bool2int(checkmake(t, "len", l) < 0)
                        et |= bool2int(r != nil && checkmake(t, "cap", r) < 0)
                        if et != 0 {
-                               goto error
+                               n.Type = nil
+                               return
                        }
                        if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 {
                                Yyerror("len larger than cap in make(%v)", Tconv(t, 0))
-                               goto error
+                               n.Type = nil
+                               return
                        }
 
                        n.Left = l
@@ -1504,10 +1866,12 @@ reswitch:
                                typecheck(&l, Erv)
                                defaultlit(&l, Types[TINT])
                                if l.Type == nil {
-                                       goto error
+                                       n.Type = nil
+                                       return
                                }
                                if checkmake(t, "size", l) < 0 {
-                                       goto error
+                                       n.Type = nil
+                                       return
                                }
                                n.Left = l
                        } else {
@@ -1523,10 +1887,12 @@ reswitch:
                                typecheck(&l, Erv)
                                defaultlit(&l, Types[TINT])
                                if l.Type == nil {
-                                       goto error
+                                       n.Type = nil
+                                       return
                                }
                                if checkmake(t, "buffer", l) < 0 {
-                                       goto error
+                                       n.Type = nil
+                                       return
                                }
                                n.Left = l
                        } else {
@@ -1538,34 +1904,38 @@ reswitch:
                if args != nil {
                        Yyerror("too many arguments to make(%v)", Tconv(t, 0))
                        n.Op = OMAKE
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.Type = t
-               goto ret
+               break OpSwitch
 
        case ONEW:
                ok |= Erv
                args := n.List
                if args == nil {
                        Yyerror("missing argument to new")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                l := args.N
                typecheck(&l, Etype)
                t := l.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if args.Next != nil {
                        Yyerror("too many arguments to new(%v)", Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.Left = l
                n.Type = Ptrto(t)
-               goto ret
+               break OpSwitch
 
        case OPRINT,
                OPRINTN:
@@ -1580,57 +1950,63 @@ reswitch:
                        }
                }
 
-               goto ret
+               break OpSwitch
 
        case OPANIC:
                ok |= Etop
                if onearg(n, "panic") < 0 {
-                       goto error
+                       n.Type = nil
+                       return
                }
                typecheck(&n.Left, Erv)
                defaultlit(&n.Left, Types[TINTER])
                if n.Left.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               goto ret
+               break OpSwitch
 
        case ORECOVER:
                ok |= Erv | Etop
                if n.List != nil {
                        Yyerror("too many arguments to recover")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                n.Type = Types[TINTER]
-               goto ret
+               break OpSwitch
 
        case OCLOSURE:
                ok |= Erv
                typecheckclosure(n, top)
                if n.Type == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
-               goto ret
+               break OpSwitch
 
        case OITAB:
                ok |= Erv
                typecheck(&n.Left, Erv)
                t := n.Left.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if t.Etype != TINTER {
                        Fatal("OITAB of %v", Tconv(t, 0))
                }
                n.Type = Ptrto(Types[TUINTPTR])
-               goto ret
+               break OpSwitch
 
        case OSPTR:
                ok |= Erv
                typecheck(&n.Left, Erv)
                t := n.Left.Type
                if t == nil {
-                       goto error
+                       n.Type = nil
+                       return
                }
                if !Isslice(t) && t.Etype != TSTRING {
                        Fatal("OSPTR of %v", Tconv(t, 0))
@@ -1640,22 +2016,22 @@ reswitch:
                } else {
                        n.Type = Ptrto(t.Type)
                }
-               goto ret
+               break OpSwitch
 
        case OCLOSUREVAR:
                ok |= Erv
-               goto ret
+               break OpSwitch
 
        case OCFUNC:
                ok |= Erv
                typecheck(&n.Left, Erv)
                n.Type = Types[TUINTPTR]
-               goto ret
+               break OpSwitch
 
        case OCONVNOP:
                ok |= Erv
                typecheck(&n.Left, Erv)
-               goto ret
+               break OpSwitch
 
                /*
                 * statements
@@ -1669,12 +2045,12 @@ reswitch:
                if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
                        n.Left.Defn = n
                }
-               goto ret
+               break OpSwitch
 
        case OAS2:
                ok |= Etop
                typecheckas2(n)
-               goto ret
+               break OpSwitch
 
        case OBREAK,
                OCONTINUE,
@@ -1684,12 +2060,12 @@ reswitch:
                OXFALL,
                OVARKILL:
                ok |= Etop
-               goto ret
+               break OpSwitch
 
        case OLABEL:
                ok |= Etop
                decldepth++
-               goto ret
+               break OpSwitch
 
        case ODEFER:
                ok |= Etop
@@ -1697,13 +2073,13 @@ reswitch:
                if n.Left.Diag == 0 {
                        checkdefergo(n)
                }
-               goto ret
+               break OpSwitch
 
        case OPROC:
                ok |= Etop
                typecheck(&n.Left, Etop|Eproc|Erv)
                checkdefergo(n)
-               goto ret
+               break OpSwitch
 
        case OFOR:
                ok |= Etop
@@ -1719,7 +2095,7 @@ reswitch:
                typecheck(&n.Nincr, Etop)
                typechecklist(n.Nbody, Etop)
                decldepth--
-               goto ret
+               break OpSwitch
 
        case OIF:
                ok |= Etop
@@ -1733,7 +2109,7 @@ reswitch:
                }
                typechecklist(n.Nbody, Etop)
                typechecklist(n.Nelse, Etop)
-               goto ret
+               break OpSwitch
 
        case ORETURN:
                ok |= Etop
@@ -1744,53 +2120,55 @@ reswitch:
                }
                if Curfn == nil {
                        Yyerror("return outside function")
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                if Curfn.Type.Outnamed != 0 && n.List == nil {
-                       goto ret
+                       break OpSwitch
                }
                typecheckaste(ORETURN, nil, 0, getoutargx(Curfn.Type), n.List, "return argument")
-               goto ret
+               break OpSwitch
 
        case ORETJMP:
                ok |= Etop
-               goto ret
+               break OpSwitch
 
        case OSELECT:
                ok |= Etop
                typecheckselect(n)
-               goto ret
+               break OpSwitch
 
        case OSWITCH:
                ok |= Etop
                typecheckswitch(n)
-               goto ret
+               break OpSwitch
 
        case ORANGE:
                ok |= Etop
                typecheckrange(n)
-               goto ret
+               break OpSwitch
 
        case OTYPESW:
                Yyerror("use of .(type) outside type switch")
-               goto error
+               n.Type = nil
+               return
 
        case OXCASE:
                ok |= Etop
                typechecklist(n.List, Erv)
                typechecklist(n.Nbody, Etop)
-               goto ret
+               break OpSwitch
 
        case ODCLFUNC:
                ok |= Etop
                typecheckfunc(n)
-               goto ret
+               break OpSwitch
 
        case ODCLCONST:
                ok |= Etop
                typecheck(&n.Left, Erv)
-               goto ret
+               break OpSwitch
 
        case ODCLTYPE:
                ok |= Etop
@@ -1798,264 +2176,10 @@ reswitch:
                if incannedimport == 0 {
                        checkwidth(n.Left.Type)
                }
-               goto ret
+               break OpSwitch
        }
 
-       goto ret
-
-arith:
-       if op == OLSH || op == ORSH {
-               defaultlit(&r, Types[TUINT])
-               n.Right = r
-               t := r.Type
-               if !Isint[t.Etype] || Issigned[t.Etype] {
-                       Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0))
-                       goto error
-               }
-
-               t = l.Type
-               if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] {
-                       Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
-                       goto error
-               }
-
-               // no defaultlit for left
-               // the outer context gives the type
-               n.Type = l.Type
-
-               goto ret
-       }
-
-       // ideal mixed with non-ideal
-       defaultlit2(&l, &r, 0)
-
-       n.Left = l
-       n.Right = r
-       if l.Type == nil || r.Type == nil {
-               goto error
-       }
-       t = l.Type
-       if t.Etype == TIDEAL {
-               t = r.Type
-       }
-       et = int(t.Etype)
-       if et == TIDEAL {
-               et = TINT
-       }
-       aop = 0
-       if iscmp[n.Op] && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
-               // comparison is okay as long as one side is
-               // assignable to the other.  convert so they have
-               // the same type.
-               //
-               // the only conversion that isn't a no-op is concrete == interface.
-               // in that case, check comparability of the concrete type.
-               // The conversion allocates, so only do it if the concrete type is huge.
-               if r.Type.Etype != TBLANK {
-                       aop = assignop(l.Type, r.Type, nil)
-                       if aop != 0 {
-                               if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ {
-                                       Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type))
-                                       goto error
-                               }
-
-                               dowidth(l.Type)
-                               if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 {
-                                       l = Nod(aop, l, nil)
-                                       l.Type = r.Type
-                                       l.Typecheck = 1
-                                       n.Left = l
-                               }
-
-                               t = r.Type
-                               goto converted
-                       }
-               }
-
-               if l.Type.Etype != TBLANK {
-                       aop = assignop(r.Type, l.Type, nil)
-                       if aop != 0 {
-                               if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ {
-                                       Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type))
-                                       goto error
-                               }
-
-                               dowidth(r.Type)
-                               if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 {
-                                       r = Nod(aop, r, nil)
-                                       r.Type = l.Type
-                                       r.Typecheck = 1
-                                       n.Right = r
-                               }
-
-                               t = l.Type
-                       }
-               }
-
-       converted:
-               et = int(t.Etype)
-       }
-
-       if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
-               defaultlit2(&l, &r, 1)
-               if n.Op == OASOP && n.Implicit != 0 {
-                       Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0))
-                       goto error
-               }
-
-               if Isinter(r.Type) == Isinter(l.Type) || aop == 0 {
-                       Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
-                       goto error
-               }
-       }
-
-       if !okfor[op][et] {
-               Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t))
-               goto error
-       }
-
-       // okfor allows any array == array, map == map, func == func.
-       // restrict to slice/map/func == nil and nil == slice/map/func.
-       if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ {
-               Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0))
-               goto error
-       }
-
-       if Isslice(l.Type) && !isnil(l) && !isnil(r) {
-               Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0))
-               goto error
-       }
-
-       if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
-               Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0))
-               goto error
-       }
-
-       if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
-               Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0))
-               goto error
-       }
-
-       if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ {
-               Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0))
-               goto error
-       }
-
-       t = l.Type
-       if iscmp[n.Op] {
-               evconst(n)
-               t = idealbool
-               if n.Op != OLITERAL {
-                       defaultlit2(&l, &r, 1)
-                       n.Left = l
-                       n.Right = r
-               }
-       } else if n.Op == OANDAND || n.Op == OOROR {
-               if l.Type == r.Type {
-                       t = l.Type
-               } else if l.Type == idealbool {
-                       t = r.Type
-               } else if r.Type == idealbool {
-                       t = l.Type
-               }
-       } else
-       // non-comparison operators on ideal bools should make them lose their ideal-ness
-       if t == idealbool {
-               t = Types[TBOOL]
-       }
-
-       if et == TSTRING {
-               if iscmp[n.Op] {
-                       n.Etype = n.Op
-                       n.Op = OCMPSTR
-               } else if n.Op == OADD {
-                       // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
-                       n.Op = OADDSTR
-
-                       if l.Op == OADDSTR {
-                               n.List = l.List
-                       } else {
-                               n.List = list1(l)
-                       }
-                       if r.Op == OADDSTR {
-                               n.List = concat(n.List, r.List)
-                       } else {
-                               n.List = list(n.List, r)
-                       }
-                       n.Left = nil
-                       n.Right = nil
-               }
-       }
-
-       if et == TINTER {
-               if l.Op == OLITERAL && l.Val.Ctype == CTNIL {
-                       // swap for back end
-                       n.Left = r
-
-                       n.Right = l
-               } else if r.Op == OLITERAL && r.Val.Ctype == CTNIL {
-               } else // leave alone for back end
-               if Isinter(r.Type) == Isinter(l.Type) {
-                       n.Etype = n.Op
-                       n.Op = OCMPIFACE
-               }
-       }
-
-       if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
-               if mpcmpfixc(r.Val.U.Xval, 0) == 0 {
-                       Yyerror("division by zero")
-                       goto error
-               }
-       }
-
-       n.Type = t
-       goto ret
-
-doconv:
-       ok |= Erv
-       saveorignode(n)
-       typecheck(&n.Left, Erv|top&(Eindir|Eiota))
-       convlit1(&n.Left, n.Type, true)
-       t = n.Left.Type
-       if t == nil || n.Type == nil {
-               goto error
-       }
-       n.Op = uint8(convertop(t, n.Type, &why))
-       if (n.Op) == 0 {
-               if n.Diag == 0 && n.Type.Broke == 0 {
-                       Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why)
-                       n.Diag = 1
-               }
-
-               n.Op = OCONV
-       }
-
-       switch n.Op {
-       case OCONVNOP:
-               if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] {
-                       r := Nod(OXXX, nil, nil)
-                       n.Op = OCONV
-                       n.Orig = r
-                       *r = *n
-                       n.Op = OLITERAL
-                       n.Val = n.Left.Val
-               }
-
-               // do not use stringtoarraylit.
-       // generated code and compiler memory footprint is better without it.
-       case OSTRARRAYBYTE:
-               break
-
-       case OSTRARRAYRUNE:
-               if n.Left.Op == OLITERAL {
-                       stringtoarraylit(&n)
-               }
-       }
-
-       goto ret
-
-ret:
-       t = n.Type
+       t := n.Type
        if t != nil && t.Funarg == 0 && n.Op != OTYPE {
                switch t.Etype {
                case TFUNC, // might have TANY; wait until its called
@@ -2078,18 +2202,21 @@ ret:
        evconst(n)
        if n.Op == OTYPE && top&Etype == 0 {
                Yyerror("type %v is not an expression", Tconv(n.Type, 0))
-               goto error
+               n.Type = nil
+               return
        }
 
        if top&(Erv|Etype) == Etype && n.Op != OTYPE {
                Yyerror("%v is not a type", Nconv(n, 0))
-               goto error
+               n.Type = nil
+               return
        }
 
        // TODO(rsc): simplify
        if (top&(Ecall|Erv|Etype) != 0) && top&Etop == 0 && ok&(Erv|Etype|Ecall) == 0 {
                Yyerror("%v used as value", Nconv(n, 0))
-               goto error
+               n.Type = nil
+               return
        }
 
        if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
@@ -2098,24 +2225,14 @@ ret:
                        n.Diag = 1
                }
 
-               goto error
+               n.Type = nil
+               return
        }
 
        /* TODO
        if(n->type == T)
                fatal("typecheck nil type");
        */
-       goto out
-
-badcall1:
-       Yyerror("invalid argument %v for %v", Nconv(n.Left, obj.FmtLong), Oconv(int(n.Op), 0))
-       goto error
-
-error:
-       n.Type = nil
-
-out:
-       *np = n
 }
 
 func checksliceindex(l *Node, r *Node, tp *Type) int {
@@ -2840,35 +2957,35 @@ func pushtype(n *Node, t *Type) {
 }
 
 func typecheckcomplit(np **Node) {
-       var nerr int
-       var l *Node
-       var norig *Node
-       var r *Node
-       var t *Type
-
        n := *np
        lno := lineno
+       defer func() {
+               lineno = lno
+               *np = n
+       }()
 
        if n.Right == nil {
                if n.List != nil {
                        setlineno(n.List.N)
                }
                Yyerror("missing type in composite literal")
-               goto error
+               n.Type = nil
+               return
        }
 
        // Save original node (including n->right)
-       norig = Nod(int(n.Op), nil, nil)
+       norig := Nod(int(n.Op), nil, nil)
 
        *norig = *n
 
        setlineno(n.Right)
-       l = typecheck(&n.Right, Etype|Ecomplit) /* sic */
-       t = l.Type
+       l := typecheck(&n.Right, Etype|Ecomplit) /* sic */
+       t := l.Type
        if t == nil {
-               goto error
+               n.Type = nil
+               return
        }
-       nerr = nerrors
+       nerr := nerrors
        n.Type = t
 
        if Isptr[t.Etype] {
@@ -2876,18 +2993,21 @@ func typecheckcomplit(np **Node) {
                // except when using the &T syntax, which sets implicit on the OIND.
                if n.Right.Implicit == 0 {
                        Yyerror("invalid pointer type %v for composite literal (use &%v instead)", Tconv(t, 0), Tconv(t.Type, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                // Also, the underlying type must be a struct, map, slice, or array.
                if !iscomptype(t) {
                        Yyerror("invalid pointer type %v for composite literal", Tconv(t, 0))
-                       goto error
+                       n.Type = nil
+                       return
                }
 
                t = t.Type
        }
 
+       var r *Node
        switch t.Etype {
        default:
                Yyerror("invalid type for composite literal: %v", Tconv(t, 0))
@@ -3075,7 +3195,8 @@ func typecheckcomplit(np **Node) {
        }
 
        if nerr != nerrors {
-               goto error
+               n.Type = nil
+               return
        }
 
        n.Orig = norig
@@ -3088,14 +3209,7 @@ func typecheckcomplit(np **Node) {
        }
 
        n.Orig = norig
-       *np = n
-       lineno = lno
        return
-
-error:
-       n.Type = nil
-       *np = n
-       lineno = lno
 }
 
 /*
index ed46809a37a7660fab9ebdd2f0e240fb88819dcd..0992c181cd3ab7dc91e4249bf5e3a1bbd43ccdb4 100644 (file)
@@ -3235,9 +3235,6 @@ func sliceany(n *Node, init **NodeList) *Node {
 
        // Checking src[lb:hb:cb] or src[lb:hb].
        // if chk0 || chk1 || chk2 { panicslice() }
-       var chk0 *Node // cap(src) < cb
-       var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
-       var chk2 *Node // hb < lb
 
        // All comparisons are unsigned to avoid testing < 0.
        bt := Types[Simtype[TUINT]]
@@ -3254,6 +3251,7 @@ func sliceany(n *Node, init **NodeList) *Node {
 
        bound = cheapexpr(conv(bound, bt), init)
 
+       var chk0 *Node // cap(src) < cb
        if cb != nil {
                cb = cheapexpr(conv(cb, bt), init)
                if bounded == 0 {
@@ -3264,6 +3262,7 @@ func sliceany(n *Node, init **NodeList) *Node {
                Fatal("slice3 with cb == N") // rejected by parser
        }
 
+       var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
        if hb != nil {
                hb = cheapexpr(conv(hb, bt), init)
                if bounded == 0 {
@@ -3285,6 +3284,7 @@ func sliceany(n *Node, init **NodeList) *Node {
                hb = cheapexpr(conv(hb, bt), init)
        }
 
+       var chk2 *Node // hb < lb
        if lb != nil {
                lb = cheapexpr(conv(lb, bt), init)
                if bounded == 0 {
@@ -3432,14 +3432,6 @@ func walkcompare(np **Node, init **NodeList) {
                r = n.Left
        }
 
-       var call *Node
-       var a *Node
-       var cmpl *Node
-       var cmpr *Node
-       var andor int
-       var expr *Node
-       var needsize int
-       var t *Type
        if l != nil {
                x := temp(r.Type)
                ok := temp(Types[TBOOL])
@@ -3464,12 +3456,13 @@ func walkcompare(np **Node, init **NodeList) {
                        r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
                }
                *init = list(*init, expr)
-               goto ret
+               finishcompare(np, n, r, init)
+               return
        }
 
        // Must be comparison of array or struct.
        // Otherwise back end handles it.
-       t = n.Left.Type
+       t := n.Left.Type
 
        switch t.Etype {
        default:
@@ -3484,11 +3477,11 @@ func walkcompare(np **Node, init **NodeList) {
                break
        }
 
-       cmpl = n.Left
+       cmpl := n.Left
        for cmpl != nil && cmpl.Op == OCONVNOP {
                cmpl = cmpl.Left
        }
-       cmpr = n.Right
+       cmpr := n.Right
        for cmpr != nil && cmpr.Op == OCONVNOP {
                cmpr = cmpr.Left
        }
@@ -3498,7 +3491,7 @@ func walkcompare(np **Node, init **NodeList) {
        }
 
        l = temp(Ptrto(t))
-       a = Nod(OAS, l, Nod(OADDR, cmpl, nil))
+       a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
        a.Right.Etype = 1 // addr does not escape
        typecheck(&a, Etop)
        *init = list(*init, a)
@@ -3509,12 +3502,12 @@ func walkcompare(np **Node, init **NodeList) {
        typecheck(&a, Etop)
        *init = list(*init, a)
 
-       expr = nil
-       andor = OANDAND
+       andor := OANDAND
        if n.Op == ONE {
                andor = OOROR
        }
 
+       var expr *Node
        if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
                // Four or fewer elements of a basic type.
                // Unroll comparisons.
@@ -3534,8 +3527,8 @@ func walkcompare(np **Node, init **NodeList) {
                if expr == nil {
                        expr = Nodbool(n.Op == OEQ)
                }
-               r = expr
-               goto ret
+               finishcompare(np, n, expr, init)
+               return
        }
 
        if t.Etype == TSTRUCT && countfield(t) <= 4 {
@@ -3560,12 +3553,13 @@ func walkcompare(np **Node, init **NodeList) {
                if expr == nil {
                        expr = Nodbool(n.Op == OEQ)
                }
-               r = expr
-               goto ret
+               finishcompare(np, n, expr, init)
+               return
        }
 
        // Chose not to inline.  Call equality function directly.
-       call = Nod(OCALL, eqfor(t, &needsize), nil)
+       var needsize int
+       call := Nod(OCALL, eqfor(t, &needsize), nil)
 
        call.List = list(call.List, l)
        call.List = list(call.List, r)
@@ -3576,19 +3570,23 @@ func walkcompare(np **Node, init **NodeList) {
        if n.Op != OEQ {
                r = Nod(ONOT, r, nil)
        }
-       goto ret
 
-ret:
-       typecheck(&r, Erv)
-       walkexpr(&r, init)
+       finishcompare(np, n, r, init)
+       return
+}
+
+func finishcompare(np **Node, n, r *Node, init **NodeList) {
+       // Using np here to avoid passing &r to typecheck.
+       *np = r
+       typecheck(np, Erv)
+       walkexpr(np, init)
+       r = *np
        if r.Type != n.Type {
                r = Nod(OCONVNOP, r, nil)
                r.Type = n.Type
                r.Typecheck = 1
+               *np = r
        }
-
-       *np = r
-       return
 }
 
 func samecheap(a *Node, b *Node) bool {