// Skip over parens.
for n.Op() == ir.OPAREN {
- n = n.Left()
+ n = n.(*ir.ParenExpr).Left()
}
// Resolve definition of name and value of iota lazily.
return n
}
- if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
- base.Errorf("use of builtin %v not in function call", n.Sym())
- n.SetType(nil)
- return n
+ if n.Op() == ir.ONAME {
+ if n.SubOp() != 0 && top&ctxCallee == 0 {
+ base.Errorf("use of builtin %v not in function call", n.Sym())
+ n.SetType(nil)
+ return n
+ }
}
typecheckdef(n)
ir.OOROR,
ir.OSUB,
ir.OXOR:
- var l ir.Node
- var op ir.Op
- var r ir.Node
+ var l, r ir.Node
+ var setLR func()
+ switch n := n.(type) {
+ case *ir.AssignOpStmt:
+ l, r = n.Left(), n.Right()
+ setLR = func() { n.SetLeft(l); n.SetRight(r) }
+ case *ir.BinaryExpr:
+ l, r = n.Left(), n.Right()
+ setLR = func() { n.SetLeft(l); n.SetRight(r) }
+ case *ir.LogicalExpr:
+ l, r = n.Left(), n.Right()
+ setLR = func() { n.SetLeft(l); n.SetRight(r) }
+ }
+ l = typecheck(l, ctxExpr)
+ r = typecheck(r, ctxExpr)
+ setLR()
+ if l.Type() == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ op := n.Op()
if n.Op() == ir.OASOP {
- n.SetLeft(typecheck(n.Left(), ctxExpr))
- n.SetRight(typecheck(n.Right(), ctxExpr))
- l = n.Left()
- r = n.Right()
- checkassign(n, n.Left())
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
+ checkassign(n, l)
if n.Implicit() && !okforarith[l.Type().Kind()] {
base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
n.SetType(nil)
}
// TODO(marvin): Fix Node.EType type union.
op = n.SubOp()
- } else {
- n.SetLeft(typecheck(n.Left(), ctxExpr))
- n.SetRight(typecheck(n.Right(), ctxExpr))
- l = n.Left()
- r = n.Right()
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- op = n.Op()
}
if op == ir.OLSH || op == ir.ORSH {
r = defaultlit(r, types.Types[types.TUINT])
- n.SetRight(r)
+ setLR()
t := r.Type()
if !t.IsInteger() {
base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
// ideal mixed with non-ideal
l, r = defaultlit2(l, r, false)
+ setLR()
- n.SetLeft(l)
- n.SetRight(r)
if l.Type() == nil || r.Type() == nil {
n.SetType(nil)
return n
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
l.SetTypecheck(1)
- n.SetLeft(l)
+ setLR()
}
t = r.Type()
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
r.SetTypecheck(1)
- n.SetRight(r)
+ setLR()
}
t = l.Type()
if iscmp[n.Op()] {
t = types.UntypedBool
n.SetType(t)
- n = evalConst(n)
- if n.Op() != ir.OLITERAL {
- l, r = defaultlit2(l, r, true)
- n.SetLeft(l)
- n.SetRight(r)
+ if con := evalConst(n); con.Op() == ir.OLITERAL {
+ return con
}
+ l, r = defaultlit2(l, r, true)
+ setLR()
+ return n
}
if et == types.TSTRING && n.Op() == ir.OADD {
// create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ var add *ir.AddStringExpr
if l.Op() == ir.OADDSTR {
- orig := n
- n = l
- n.SetPos(orig.Pos())
+ add = l.(*ir.AddStringExpr)
+ add.SetPos(n.Pos())
} else {
- n = ir.NodAt(n.Pos(), ir.OADDSTR, nil, nil)
- n.PtrList().Set1(l)
+ add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
}
if r.Op() == ir.OADDSTR {
- n.PtrList().AppendNodes(r.PtrList())
+ add.PtrList().AppendNodes(r.PtrList())
} else {
- n.PtrList().Append(r)
+ add.PtrList().Append(r)
}
+ add.SetType(t)
+ return add
}
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
return n
case ir.OCOMPLIT:
- return typecheckcomplit(n)
+ return typecheckcomplit(n.(*ir.CompLitExpr))
case ir.OXDOT, ir.ODOT:
+ n := n.(*ir.SelectorExpr)
if n.Op() == ir.OXDOT {
- n = adddot(n)
+ n = adddot(n).(*ir.SelectorExpr)
n.SetOp(ir.ODOT)
if n.Left() == nil {
n.SetType(nil)
}
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
- n = typecheckpartialcall(n, s)
+ return typecheckpartialcall(n, s)
}
return n
return n
}
- n.SetLeft(nodAddr(n.Left()))
- n.Left().SetImplicit(true)
- n.SetLeft(typecheck(n.Left(), ctxExpr))
+ addr := nodAddr(n.Left())
+ addr.SetImplicit(true)
+ n.SetLeft(typecheck(addr, ctxExpr))
l = n.Left()
}
t := l.Type()
// call and call like
case ir.OCALL:
- n.(*ir.CallExpr).Use = ir.CallUseExpr
+ n := n.(*ir.CallExpr)
+ n.Use = ir.CallUseExpr
if top == ctxStmt {
- n.(*ir.CallExpr).Use = ir.CallUseStmt
+ n.Use = ir.CallUseStmt
}
typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType|ctxCallee))
l := n.Left()
- if l.Op() == ir.ONAME && l.SubOp() != 0 {
+ if l.Op() == ir.ONAME && l.(*ir.Name).SubOp() != 0 {
if n.IsDDD() && l.SubOp() != ir.OAPPEND {
base.Errorf("invalid use of ... with builtin %v", l)
}
return n
}
- n = ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
+ n := ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
n.SetType(l.Type())
return typecheck1(n, top)
}
if t.NumResults() == 1 {
n.SetType(l.Type().Results().Field(0).Type)
- if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME && isRuntimePkg(n.Left().Sym().Pkg) && n.Left().Sym().Name == "getg" {
- // Emit code for runtime.getg() directly instead of calling function.
- // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
- // so that the ordering pass can make sure to preserve the semantics of the original code
- // (in particular, the exact time of the function call) by introducing temporaries.
- // In this case, we know getg() always returns the same result within a given function
- // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
- n.SetOp(ir.OGETG)
+ if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME {
+ if sym := n.Left().(*ir.Name).Sym(); isRuntimePkg(sym.Pkg) && sym.Name == "getg" {
+ // Emit code for runtime.getg() directly instead of calling function.
+ // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
+ // so that the ordering pass can make sure to preserve the semantics of the original code
+ // (in particular, the exact time of the function call) by introducing temporaries.
+ // In this case, we know getg() always returns the same result within a given function
+ // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
+ n.SetOp(ir.OGETG)
+ }
}
return n
}
return n
case ir.OCONV:
+ n := n.(*ir.ConvExpr)
checkwidth(n.Type()) // ensure width is calculated for backend
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(convlit1(n.Left(), n.Type(), true, nil))
case ir.OSTR2RUNES:
if n.Left().Op() == ir.OLITERAL {
- n = stringtoruneslit(n)
+ return stringtoruneslit(n)
}
}
return n
}
nn.SetType(t)
- n = nn
- return n
+ return nn
case ir.ONEW:
if n.Left() == nil {
// statements
case ir.OAS:
+ n := n.(*ir.AssignStmt)
typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here.
return n
case ir.OAS2:
- typecheckas2(n)
+ typecheckas2(n.(*ir.AssignListStmt))
return n
case ir.OBREAK,
return n
case ir.ODEFER, ir.OGO:
+ n := n.(*ir.GoDeferStmt)
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
if !n.Left().Diag() {
checkdefergo(n)
return n
case ir.OSELECT:
- typecheckselect(n)
+ typecheckselect(n.(*ir.SelectStmt))
return n
case ir.OSWITCH:
- typecheckswitch(n)
+ typecheckswitch(n.(*ir.SwitchStmt))
return n
case ir.ORANGE:
- typecheckrange(n)
+ typecheckrange(n.(*ir.RangeStmt))
return n
case ir.OTYPESW:
}
func typecheckargs(n ir.Node) {
- if n.List().Len() != 1 || n.IsDDD() {
- typecheckslice(n.List().Slice(), ctxExpr)
+ var list []ir.Node
+ switch n := n.(type) {
+ default:
+ base.Fatalf("typecheckargs %+v", n.Op())
+ case *ir.CallExpr:
+ list = n.List().Slice()
+ if n.IsDDD() {
+ typecheckslice(list, ctxExpr)
+ return
+ }
+ case *ir.ReturnStmt:
+ list = n.List().Slice()
+ }
+ if len(list) != 1 {
+ typecheckslice(list, ctxExpr)
return
}
- typecheckslice(n.List().Slice(), ctxExpr|ctxMultiOK)
- t := n.List().First().Type()
+ typecheckslice(list, ctxExpr|ctxMultiOK)
+ t := list[0].Type()
if t == nil || !t.IsFuncArgStruct() {
return
}
}
as := ir.Nod(ir.OAS2, nil, nil)
- as.PtrRlist().AppendNodes(n.PtrList())
+ as.PtrRlist().Append(list...)
// If we're outside of function context, then this call will
// be executed during the generated init function. However,
if static {
Curfn = initTodo
}
+ list = nil
for _, f := range t.FieldSlice() {
t := temp(f.Type)
as.PtrInit().Append(ir.Nod(ir.ODCL, t, nil))
as.PtrList().Append(t)
- n.PtrList().Append(t)
+ list = append(list, t)
}
if static {
Curfn = nil
}
+ switch n := n.(type) {
+ case *ir.CallExpr:
+ n.PtrList().Set(list)
+ case *ir.ReturnStmt:
+ n.PtrList().Set(list)
+ }
+
n.PtrInit().Append(typecheck(as, ctxStmt))
}
return true
}
-func checkdefergo(n ir.Node) {
+func checkdefergo(n *ir.GoDeferStmt) {
what := "defer"
if n.Op() == ir.OGO {
what = "go"
if !t.IsArray() {
return n
}
- n = ir.Nod(ir.ODEREF, n, nil)
- n.SetImplicit(true)
- n = typecheck(n, ctxExpr)
- return n
+ star := ir.Nod(ir.ODEREF, n, nil)
+ star.SetImplicit(true)
+ return typecheck(star, ctxExpr)
}
-func needOneArg(n ir.Node, f string, args ...interface{}) (ir.Node, bool) {
+func needOneArg(n *ir.CallExpr, f string, args ...interface{}) (ir.Node, bool) {
if n.List().Len() == 0 {
p := fmt.Sprintf(f, args...)
base.Errorf("missing argument to %s: %v", p, n)
return n.List().First(), true
}
-func needTwoArgs(n ir.Node) (ir.Node, ir.Node, bool) {
+func needTwoArgs(n *ir.CallExpr) (ir.Node, ir.Node, bool) {
if n.List().Len() != 2 {
if n.List().Len() < 2 {
base.Errorf("not enough arguments in call to %v", n)
// typecheckMethodExpr checks selector expressions (ODOT) where the
// base expression is a type expression (OTYPE).
-func typecheckMethodExpr(n ir.Node) (res ir.Node) {
+func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckMethodExpr", n)(&res)
}
return t
}
-func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
+func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
s := n.Sym()
dowidth(t)
n.SetType(f1.Type)
if t.IsInterface() {
if n.Left().Type().IsPtr() {
- n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil)) // implicitstar
- n.Left().SetImplicit(true)
- n.SetLeft(typecheck(n.Left(), ctxExpr))
+ star := ir.Nod(ir.ODEREF, n.Left(), nil)
+ star.SetImplicit(true)
+ n.SetLeft(typecheck(star, ctxExpr))
}
n.SetOp(ir.ODOTINTER)
}
- n.(*ir.SelectorExpr).Selection = f1
+ n.Selection = f1
return f1
}
if !types.Identical(rcvr, tt) {
if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
checklvalue(n.Left(), "call pointer method on")
- n.SetLeft(nodAddr(n.Left()))
- n.Left().SetImplicit(true)
- n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
+ addr := nodAddr(n.Left())
+ addr.SetImplicit(true)
+ n.SetLeft(typecheck(addr, ctxType|ctxExpr))
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
- n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil))
- n.Left().SetImplicit(true)
- n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
+ star := ir.Nod(ir.ODEREF, n.Left(), nil)
+ star.SetImplicit(true)
+ n.SetLeft(typecheck(star, ctxType|ctxExpr))
} else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
base.Errorf("calling method %v with receiver %L requires explicit dereference", n.Sym(), n.Left())
for tt.IsPtr() {
if rcvr.IsPtr() && !tt.Elem().IsPtr() {
break
}
- n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil))
- n.Left().SetImplicit(true)
- n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
+ star := ir.Nod(ir.ODEREF, n.Left(), nil)
+ star.SetImplicit(true)
+ n.SetLeft(typecheck(star, ctxType|ctxExpr))
tt = tt.Elem()
}
} else {
}
}
- pll := n
- ll := n.Left()
- for ll.Left() != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
- pll = ll
- ll = ll.Left()
+ implicit, ll := n.Implicit(), n.Left()
+ for ll != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
+ switch l := ll.(type) {
+ case *ir.SelectorExpr:
+ implicit, ll = l.Implicit(), l.Left()
+ case *ir.StarExpr:
+ implicit, ll = l.Implicit(), l.Left()
+ }
}
- if pll.Implicit() && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
+ if implicit && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
// It is invalid to automatically dereference a named pointer type when selecting a method.
// Make n.Left == ll to clarify error message.
n.SetLeft(ll)
n.SetOffset(f2.Offset)
n.SetType(f2.Type)
n.SetOp(ir.ODOTMETH)
- n.(*ir.SelectorExpr).Selection = f2
+ n.Selection = f2
return f2
}
// pushtype adds elided type information for composite literals if
// appropriate, and returns the resulting expression.
-func pushtype(n ir.Node, t *types.Type) ir.Node {
- if n == nil || n.Op() != ir.OCOMPLIT || n.Right() != nil {
+func pushtype(nn ir.Node, t *types.Type) ir.Node {
+ if nn == nil || nn.Op() != ir.OCOMPLIT {
+ return nn
+ }
+ n := nn.(*ir.CompLitExpr)
+ if n.Right() != nil {
return n
}
// For *T, return &T{...}.
n.SetRight(ir.TypeNode(t.Elem()))
- n = nodAddrAt(n.Pos(), n)
- n.SetImplicit(true)
+ addr := ir.NodAt(n.Pos(), ir.OADDR, n, nil)
+ addr.SetImplicit(true)
+ return addr
}
-
return n
}
// The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left)
-func typecheckcomplit(n ir.Node) (res ir.Node) {
+func typecheckcomplit(n *ir.CompLitExpr) (res ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckcomplit", n)(&res)
}
}
// Save original node (including n.Right)
- n.(ir.OrigNode).SetOrig(ir.Copy(n))
+ n.SetOrig(ir.Copy(n))
setlineno(n.Right())
base.Errorf("missing key in map literal")
continue
}
+ l := l.(*ir.KeyExpr)
r := l.Left()
r = pushtype(r, t.Key())
}
// No pushtype allowed here. Must name fields for that.
n1 = assignconv(n1, f.Type, "field value")
- n1 = nodSym(ir.OSTRUCTKEY, n1, f.Sym)
- n1.SetOffset(f.Offset)
- ls[i] = n1
+ sk := nodSym(ir.OSTRUCTKEY, n1, f.Sym)
+ sk.SetOffset(f.Offset)
+ ls[i] = sk
}
if len(ls) < t.NumFields() {
base.Errorf("too few values in %v", n)
setlineno(l)
if l.Op() == ir.OKEY {
- key := l.Left()
+ kv := l.(*ir.KeyExpr)
+ key := kv.Left()
// Sym might have resolved to name in other top-level
// package, because of import dot. Redirect to correct sym
continue
}
- l = ir.NewStructKeyExpr(l.Pos(), s, l.Right())
+ l = ir.NewStructKeyExpr(l.Pos(), s, kv.Right())
ls[i] = l
}
ls[i] = typecheck(ls[i], ctxExpr)
continue
}
+ l := l.(*ir.StructKeyExpr)
f := lookdot1(nil, l.Sym(), t, t.Fields(), 0)
if f == nil {
for i, elt := range elts {
setlineno(elt)
r := elts[i]
- var kv ir.Node
+ var kv *ir.KeyExpr
if elt.Op() == ir.OKEY {
+ elt := elt.(*ir.KeyExpr)
elt.SetLeft(typecheck(elt.Left(), ctxExpr))
key = indexconst(elt.Left())
if key < 0 {
}
switch {
- case n.Op() == ir.ODOT && n.Left().Op() == ir.OINDEXMAP:
+ case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).Left().Op() == ir.OINDEXMAP:
base.Errorf("cannot assign to struct field %v in map", n)
- case (n.Op() == ir.OINDEX && n.Left().Type().IsString()) || n.Op() == ir.OSLICESTR:
+ case (n.Op() == ir.OINDEX && n.(*ir.IndexExpr).Left().Type().IsString()) || n.Op() == ir.OSLICESTR:
base.Errorf("cannot assign to %v (strings are immutable)", n)
case n.Op() == ir.OLITERAL && n.Sym() != nil && isGoConst(n):
base.Errorf("cannot assign to %v (declared const)", n)
return l == r
case ir.ODOT, ir.ODOTPTR:
+ l := l.(*ir.SelectorExpr)
+ r := r.(*ir.SelectorExpr)
return l.Sym() != nil && r.Sym() != nil && l.Sym() == r.Sym() && samesafeexpr(l.Left(), r.Left())
- case ir.ODEREF, ir.OCONVNOP,
- ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG:
+ case ir.ODEREF:
+ l := l.(*ir.StarExpr)
+ r := r.(*ir.StarExpr)
+ return samesafeexpr(l.Left(), r.Left())
+
+ case ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG:
+ l := l.(*ir.UnaryExpr)
+ r := r.(*ir.UnaryExpr)
+ return samesafeexpr(l.Left(), r.Left())
+
+ case ir.OCONVNOP:
+ l := l.(*ir.ConvExpr)
+ r := r.(*ir.ConvExpr)
return samesafeexpr(l.Left(), r.Left())
case ir.OCONV:
+ l := l.(*ir.ConvExpr)
+ r := r.(*ir.ConvExpr)
// Some conversions can't be reused, such as []byte(str).
// Allow only numeric-ish types. This is a bit conservative.
return issimple[l.Type().Kind()] && samesafeexpr(l.Left(), r.Left())
- case ir.OINDEX, ir.OINDEXMAP,
- ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
+ case ir.OINDEX, ir.OINDEXMAP:
+ l := l.(*ir.IndexExpr)
+ r := r.(*ir.IndexExpr)
+ return samesafeexpr(l.Left(), r.Left()) && samesafeexpr(l.Right(), r.Right())
+
+ case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
+ l := l.(*ir.BinaryExpr)
+ r := r.(*ir.BinaryExpr)
return samesafeexpr(l.Left(), r.Left()) && samesafeexpr(l.Right(), r.Right())
case ir.OLITERAL:
// type check assignment.
// if this assignment is the definition of a var on the left side,
// fill in the var's type.
-func typecheckas(n ir.Node) {
+func typecheckas(n *ir.AssignStmt) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckas", n)(nil)
}
checkassign(n, n.Left())
if n.Right() != nil && n.Right().Type() != nil {
if n.Right().Type().IsFuncArgStruct() {
- base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Right().Left(), n.Right().Type().NumFields())
+ base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Right().(*ir.CallExpr).Left(), n.Right().Type().NumFields())
// Multi-value RHS isn't actually valid for OAS; nil out
// to indicate failed typechecking.
n.Right().SetType(nil)
}
}
-func typecheckas2(n ir.Node) {
+func typecheckas2(n *ir.AssignListStmt) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckas2", n)(nil)
}
// The result of stringtoruneslit MUST be assigned back to n, e.g.
// n.Left = stringtoruneslit(n.Left)
-func stringtoruneslit(n ir.Node) ir.Node {
+func stringtoruneslit(n *ir.ConvExpr) ir.Node {
if n.Left().Op() != ir.OLITERAL || n.Left().Val().Kind() != constant.String {
base.Fatalf("stringtoarraylit %v", n)
}
case ir.OBREAK:
if n.Sym() == nil {
- if implicit != nil {
- implicit.SetHasBreak(true)
- }
+ setHasBreak(implicit)
} else {
- if lab := labels[n.Sym()]; lab != nil {
- lab.SetHasBreak(true)
- }
+ setHasBreak(labels[n.Sym()])
}
- case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OTYPESW, ir.OSELECT, ir.ORANGE:
+ case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OSELECT, ir.ORANGE:
old := implicit
implicit = n
- sym := n.Sym()
+ var sym *types.Sym
+ switch n := n.(type) {
+ case *ir.ForStmt:
+ sym = n.Sym()
+ case *ir.RangeStmt:
+ sym = n.Sym()
+ case *ir.SelectStmt:
+ sym = n.Sym()
+ case *ir.SwitchStmt:
+ sym = n.Sym()
+ }
if sym != nil {
if labels == nil {
// Map creation delayed until we need it - most functions don't.
mark(fn)
}
+func controlLabel(n ir.Node) *types.Sym {
+ switch n := n.(type) {
+ default:
+ base.Fatalf("controlLabel %+v", n.Op())
+ return nil
+ case *ir.ForStmt:
+ return n.Sym()
+ case *ir.RangeStmt:
+ return n.Sym()
+ case *ir.SelectStmt:
+ return n.Sym()
+ case *ir.SwitchStmt:
+ return n.Sym()
+ }
+}
+
+func setHasBreak(n ir.Node) {
+ switch n := n.(type) {
+ default:
+ base.Fatalf("setHasBreak %+v", n.Op())
+ case nil:
+ // ignore
+ case *ir.ForStmt:
+ n.SetHasBreak(true)
+ case *ir.RangeStmt:
+ n.SetHasBreak(true)
+ case *ir.SelectStmt:
+ n.SetHasBreak(true)
+ case *ir.SwitchStmt:
+ n.SetHasBreak(true)
+ }
+}
+
// isTermNodes reports whether the Nodes list ends with a terminating statement.
func isTermNodes(l ir.Nodes) bool {
s := l.Slice()
case ir.OIF:
return isTermNodes(n.Body()) && isTermNodes(n.Rlist())
- case ir.OSWITCH, ir.OTYPESW, ir.OSELECT:
+ case ir.OSWITCH:
if n.HasBreak() {
return false
}
def := false
- for _, n1 := range n.List().Slice() {
- if !isTermNodes(n1.Body()) {
+ for _, cas := range n.List().Slice() {
+ cas := cas.(*ir.CaseStmt)
+ if !isTermNodes(cas.Body()) {
return false
}
- if n1.List().Len() == 0 { // default
+ if cas.List().Len() == 0 { // default
def = true
}
}
+ return def
- if n.Op() != ir.OSELECT && !def {
+ case ir.OSELECT:
+ if n.HasBreak() {
return false
}
+ for _, cas := range n.List().Slice() {
+ cas := cas.(*ir.CaseStmt)
+ if !isTermNodes(cas.Body()) {
+ return false
+ }
+ }
return true
}