cmd/internal/gc: manual goto removal + grind to move var decls

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>
diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go
index 374d5e3..58b0c36 100644
--- a/src/cmd/5g/ggen.go
+++ b/src/cmd/5g/ggen.go
@@ -78,7 +78,7 @@
 		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 {
diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go
index b8547dd..f2ba6e2 100644
--- a/src/cmd/5g/gsubr.go
+++ b/src/cmd/5g/gsubr.go
@@ -766,12 +766,14 @@
 	// 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 @@
 
 	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 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 @@
 		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 @@
 
 			n1.Type = n.Type
 			n1.Xoffset += oary[0]
-			gc.Naddr(&n1, a, 1)
+			*a = gc.Naddr(&n1, 1)
 			return true
 		}
 
@@ -1356,7 +1358,7 @@
 		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:
diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go
index 8e28215..0b0d6b3 100644
--- a/src/cmd/6g/cgen.go
+++ b/src/cmd/6g/cgen.go
@@ -1115,8 +1115,6 @@
 		return
 	}
 
-	var nr *gc.Node
-
 	for n.Op == gc.OCONVNOP {
 		n = n.Left
 		if n.Ninit != nil {
@@ -1125,6 +1123,7 @@
 	}
 
 	var nl *gc.Node
+	var nr *gc.Node
 	switch n.Op {
 	default:
 		goto def
diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go
index 2934f1e..45242b3 100644
--- a/src/cmd/6g/ggen.go
+++ b/src/cmd/6g/ggen.go
@@ -503,7 +503,6 @@
 		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 @@
 		gc.Patch(p1, gc.Pc)
 	}
 
+	var p2 *obj.Prog
 	if check != 0 {
 		gc.Nodconst(&n4, t, -1)
 		gins(optoas(gc.OCMP, t), &n3, &n4)
diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go
index 73afb93..719a1fe 100644
--- a/src/cmd/6g/gsubr.go
+++ b/src/cmd/6g/gsubr.go
@@ -314,7 +314,6 @@
 	}
 
 	// 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 @@
 
 	// 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 @@
 	}
 
 	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 @@
 		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 @@
 
 			n1.Type = n.Type
 			n1.Xoffset += oary[0]
-			gc.Naddr(&n1, a, 1)
+			*a = gc.Naddr(&n1, 1)
 			return true
 		}
 
@@ -1454,7 +1457,7 @@
 		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:
diff --git a/src/cmd/6g/peep.go b/src/cmd/6g/peep.go
index 7eff574..a967bba 100644
--- a/src/cmd/6g/peep.go
+++ b/src/cmd/6g/peep.go
@@ -825,8 +825,7 @@
 	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
diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go
index 6931ea8..95ec01a 100644
--- a/src/cmd/8g/gsubr.go
+++ b/src/cmd/8g/gsubr.go
@@ -1148,12 +1148,14 @@
 
 	// 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 @@
 	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 {
diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go
index 98357eb..d9bcfb7 100644
--- a/src/cmd/9g/ggen.go
+++ b/src/cmd/9g/ggen.go
@@ -76,7 +76,7 @@
 		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 {
diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go
index 2c51d06..1f1a43e 100644
--- a/src/cmd/9g/gsubr.go
+++ b/src/cmd/9g/gsubr.go
@@ -669,12 +669,14 @@
 
 	// 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 @@
 
 	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 {
diff --git a/src/cmd/internal/gc/closure.go b/src/cmd/internal/gc/closure.go
index c9b6981..d6f657f 100644
--- a/src/cmd/internal/gc/closure.go
+++ b/src/cmd/internal/gc/closure.go
@@ -596,7 +596,6 @@
 	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 @@
 	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))
diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go
index 8ea5d8d..a9454e6 100644
--- a/src/cmd/internal/gc/dcl.go
+++ b/src/cmd/internal/gc/dcl.go
@@ -313,7 +313,6 @@
  * 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 @@
 
 	var v *Node
 	var c *Node
+	var vv *NodeList
 	for ; vl != nil; vl = vl.Next {
 		if cl == nil {
 			Yyerror("missing value in const declaration")
diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go
index ad5e494..48a24a6 100644
--- a/src/cmd/internal/gc/gsubr.go
+++ b/src/cmd/internal/gc/gsubr.go
@@ -274,8 +274,7 @@
 	}
 }
 
-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 @@
 
 	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 @@
 		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 @@
 			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 @@
 		}
 
 	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 @@
 
 		// 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 @@
 
 		// 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 @@
 
 		// 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 @@
 			a.Width = int64(Widthint)
 		}
 	}
+	return
 }
 
 func newplist() *obj.Plist {
diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go
index 5456435..ba13cdb 100644
--- a/src/cmd/internal/gc/plive.go
+++ b/src/cmd/internal/gc/plive.go
@@ -556,13 +556,11 @@
 // 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 @@
 	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 @@
 	any := bvalloc(nvars)
 	all := bvalloc(nvars)
 	ambig := bvalloc(localswords() * obj.BitsPerPointer)
-	var msg []string
 	nmsg := int32(0)
 	startmsg := int32(0)
 
@@ -1392,6 +1389,7 @@
 	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]
 
diff --git a/src/cmd/internal/gc/range.go b/src/cmd/internal/gc/range.go
index ed50bdf..3de70ba 100644
--- a/src/cmd/internal/gc/range.go
+++ b/src/cmd/internal/gc/range.go
@@ -136,7 +136,6 @@
 
 func walkrange(n *Node) {
 	t := n.Type
-	var init *NodeList
 
 	a := n.Right
 	lno := int(setlineno(a))
@@ -154,9 +153,8 @@
 	// 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 @@
 		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 {
diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go
index 0ff8224..845aac6 100644
--- a/src/cmd/internal/gc/typecheck.go
+++ b/src/cmd/internal/gc/typecheck.go
@@ -276,44 +276,27 @@
 }
 
 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 @@
 		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 @@
 		}
 		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 @@
 
 		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 @@
 		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 @@
 				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 @@
 				} 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 @@
 
 	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 @@
 
 	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 @@
 		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 @@
 		n.Op = OTYPE
 		n.Type = tointerface(n.List)
 		if n.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 	case OTFUNC:
@@ -484,61 +480,53 @@
 		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 @@
 		OOROR,
 		OSUB,
 		OXOR:
-		ok |= Erv
-		l = typecheck(&n.Left, Erv|top&Eiota)
-		r = typecheck(&n.Right, Erv|top&Eiota)
-		if l.Type == nil || r.Type == nil {
-			goto error
+		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)
 		}
-		op = int(n.Op)
-		goto 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))
+				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 {
+			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
+			}
+		}
+
+		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 @@
 
 		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 @@
 		}
 		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 @@
 				} 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 @@
 			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 @@
 
 		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 @@
 			} 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 @@
 			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 @@
 			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 @@
 				} 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 @@
 			} else {
 				n.Type = t.Type
 			}
-			why = "string"
+			why := "string"
 			if t.Etype == TARRAY {
 				if Isfixedarray(t) {
 					why = "array"
@@ -797,7 +1043,7 @@
 			}
 
 			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 @@
 			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 @@
 		n.Etype = 0
 
 		n.Type = nil
-		goto ret
+		break OpSwitch
 
 	case OSLICE:
 		ok |= Erv
@@ -884,11 +1137,12 @@
 		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 @@
 			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 @@
 			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 @@
 		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 @@
 			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 @@
 			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 @@
 
 			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 @@
 			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 @@
 		}
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		checkwidth(t)
 
@@ -1085,7 +1357,8 @@
 			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 @@
 		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 @@
 		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 @@
 		l := n.Left
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		switch n.Op {
 		case OCAP:
@@ -1161,7 +1437,7 @@
 			}
 
 			n.Type = Types[cplxsubtype(int(t.Etype))]
-			goto ret
+			break OpSwitch
 		}
 
 		// might be constant
@@ -1188,7 +1464,12 @@
 		}
 
 		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 @@
 			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 @@
 			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 @@
 
 		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 @@
 		}
 
 		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 @@
 		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 @@
 
 		t := args.N.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 		// Unpack multiple-return result before type-checking.
@@ -1343,31 +1641,35 @@
 		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 @@
 			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 @@
 		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 @@
 			} 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 @@
 		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 @@
 			}
 
 			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 @@
 				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 @@
 				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 @@
 		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 @@
 			}
 		}
 
-		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 @@
 		} 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 @@
 		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 @@
 		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 @@
 		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 @@
 		typecheck(&n.Nincr, Etop)
 		typechecklist(n.Nbody, Etop)
 		decldepth--
-		goto ret
+		break OpSwitch
 
 	case OIF:
 		ok |= Etop
@@ -1733,7 +2109,7 @@
 		}
 		typechecklist(n.Nbody, Etop)
 		typechecklist(n.Nelse, Etop)
-		goto ret
+		break OpSwitch
 
 	case ORETURN:
 		ok |= Etop
@@ -1744,53 +2120,55 @@
 		}
 		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 @@
 		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 @@
 	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 @@
 			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 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 @@
 		// 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 @@
 	}
 
 	if nerr != nerrors {
-		goto error
+		n.Type = nil
+		return
 	}
 
 	n.Orig = norig
@@ -3088,14 +3209,7 @@
 	}
 
 	n.Orig = norig
-	*np = n
-	lineno = lno
 	return
-
-error:
-	n.Type = nil
-	*np = n
-	lineno = lno
 }
 
 /*
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go
index ed46809..0992c18 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/internal/gc/walk.go
@@ -3235,9 +3235,6 @@
 
 	// 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 @@
 
 	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 @@
 		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 @@
 		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 @@
 		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 @@
 			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 @@
 		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 @@
 	}
 
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 {