diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/swt.go')
-rw-r--r-- | src/cmd/compile/internal/gc/swt.go | 465 |
1 files changed, 234 insertions, 231 deletions
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go index 8d9fbe300e..02d38ac4b1 100644 --- a/src/cmd/compile/internal/gc/swt.go +++ b/src/cmd/compile/internal/gc/swt.go @@ -5,43 +5,47 @@ package gc import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/src" + "go/constant" + "go/token" "sort" ) // typecheckswitch typechecks a switch statement. -func typecheckswitch(n *Node) { - typecheckslice(n.Ninit.Slice(), ctxStmt) - if n.Left != nil && n.Left.Op == OTYPESW { +func typecheckswitch(n ir.Node) { + typecheckslice(n.Init().Slice(), ctxStmt) + if n.Left() != nil && n.Left().Op() == ir.OTYPESW { typecheckTypeSwitch(n) } else { typecheckExprSwitch(n) } } -func typecheckTypeSwitch(n *Node) { - n.Left.Right = typecheck(n.Left.Right, ctxExpr) - t := n.Left.Right.Type +func typecheckTypeSwitch(n ir.Node) { + n.Left().SetRight(typecheck(n.Left().Right(), ctxExpr)) + t := n.Left().Right().Type() if t != nil && !t.IsInterface() { - yyerrorl(n.Pos, "cannot type switch on non-interface value %L", n.Left.Right) + base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", n.Left().Right()) t = nil } // We don't actually declare the type switch's guarded // declaration itself. So if there are no cases, we won't // notice that it went unused. - if v := n.Left.Left; v != nil && !v.isBlank() && n.List.Len() == 0 { - yyerrorl(v.Pos, "%v declared but not used", v.Sym) + if v := n.Left().Left(); v != nil && !ir.IsBlank(v) && n.List().Len() == 0 { + base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym()) } - var defCase, nilCase *Node + var defCase, nilCase ir.Node var ts typeSet - for _, ncase := range n.List.Slice() { - ls := ncase.List.Slice() + for _, ncase := range n.List().Slice() { + ls := ncase.List().Slice() if len(ls) == 0 { // default: if defCase != nil { - yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line()) + base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase)) } else { defCase = ncase } @@ -50,65 +54,65 @@ func typecheckTypeSwitch(n *Node) { for i := range ls { ls[i] = typecheck(ls[i], ctxExpr|ctxType) n1 := ls[i] - if t == nil || n1.Type == nil { + if t == nil || n1.Type() == nil { continue } var missing, have *types.Field var ptr int switch { - case n1.isNil(): // case nil: + case ir.IsNil(n1): // case nil: if nilCase != nil { - yyerrorl(ncase.Pos, "multiple nil cases in type switch (first at %v)", nilCase.Line()) + base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase)) } else { nilCase = ncase } - case n1.Op != OTYPE: - yyerrorl(ncase.Pos, "%L is not a type", n1) - case !n1.Type.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr) && !missing.Broke(): + case n1.Op() != ir.OTYPE: + base.ErrorfAt(ncase.Pos(), "%L is not a type", n1) + case !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke(): if have != nil && !have.Broke() { - yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+ - " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left.Right, n1.Type, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) + base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+ + " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left().Right(), n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) } else if ptr != 0 { - yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+ - " (%v method has pointer receiver)", n.Left.Right, n1.Type, missing.Sym) + base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+ + " (%v method has pointer receiver)", n.Left().Right(), n1.Type(), missing.Sym) } else { - yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+ - " (missing %v method)", n.Left.Right, n1.Type, missing.Sym) + base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+ + " (missing %v method)", n.Left().Right(), n1.Type(), missing.Sym) } } - if n1.Op == OTYPE { - ts.add(ncase.Pos, n1.Type) + if n1.Op() == ir.OTYPE { + ts.add(ncase.Pos(), n1.Type()) } } - if ncase.Rlist.Len() != 0 { + if ncase.Rlist().Len() != 0 { // Assign the clause variable's type. vt := t if len(ls) == 1 { - if ls[0].Op == OTYPE { - vt = ls[0].Type - } else if ls[0].Op != OLITERAL { // TODO(mdempsky): Should be !ls[0].isNil() + if ls[0].Op() == ir.OTYPE { + vt = ls[0].Type() + } else if !ir.IsNil(ls[0]) { // Invalid single-type case; // mark variable as broken. vt = nil } } - // TODO(mdempsky): It should be possible to - // still typecheck the case body. - if vt == nil { - continue + nvar := ncase.Rlist().First() + nvar.SetType(vt) + if vt != nil { + nvar = typecheck(nvar, ctxExpr|ctxAssign) + } else { + // Clause variable is broken; prevent typechecking. + nvar.SetTypecheck(1) + nvar.SetWalkdef(1) } - - nvar := ncase.Rlist.First() - nvar.Type = vt - nvar = typecheck(nvar, ctxExpr|ctxAssign) - ncase.Rlist.SetFirst(nvar) + ncase.Rlist().SetFirst(nvar) } - typecheckslice(ncase.Nbody.Slice(), ctxStmt) + typecheckslice(ncase.Body().Slice(), ctxStmt) } } @@ -133,19 +137,19 @@ func (s *typeSet) add(pos src.XPos, typ *types.Type) { prevs := s.m[ls] for _, prev := range prevs { if types.Identical(typ, prev.typ) { - yyerrorl(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, linestr(prev.pos)) + base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos)) return } } s.m[ls] = append(prevs, typeSetEntry{pos, typ}) } -func typecheckExprSwitch(n *Node) { - t := types.Types[TBOOL] - if n.Left != nil { - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - t = n.Left.Type +func typecheckExprSwitch(n ir.Node) { + t := types.Types[types.TBOOL] + if n.Left() != nil { + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + t = n.Left().Type() } var nilonly string @@ -153,28 +157,28 @@ func typecheckExprSwitch(n *Node) { switch { case t.IsMap(): nilonly = "map" - case t.Etype == TFUNC: + case t.Etype == types.TFUNC: nilonly = "func" case t.IsSlice(): nilonly = "slice" case !IsComparable(t): if t.IsStruct() { - yyerrorl(n.Pos, "cannot switch on %L (struct containing %v cannot be compared)", n.Left, IncomparableField(t).Type) + base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Left(), IncomparableField(t).Type) } else { - yyerrorl(n.Pos, "cannot switch on %L", n.Left) + base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Left()) } t = nil } } - var defCase *Node + var defCase ir.Node var cs constSet - for _, ncase := range n.List.Slice() { - ls := ncase.List.Slice() + for _, ncase := range n.List().Slice() { + ls := ncase.List().Slice() if len(ls) == 0 { // default: if defCase != nil { - yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line()) + base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase)) } else { defCase = ncase } @@ -185,22 +189,22 @@ func typecheckExprSwitch(n *Node) { ls[i] = typecheck(ls[i], ctxExpr) ls[i] = defaultlit(ls[i], t) n1 := ls[i] - if t == nil || n1.Type == nil { + if t == nil || n1.Type() == nil { continue } - if nilonly != "" && !n1.isNil() { - yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left) - } else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) { - yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1) + if nilonly != "" && !ir.IsNil(n1) { + base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left()) + } else if t.IsInterface() && !n1.Type().IsInterface() && !IsComparable(n1.Type()) { + base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1) } else { - op1, _ := assignop(n1.Type, t) - op2, _ := assignop(t, n1.Type) - if op1 == OXXX && op2 == OXXX { - if n.Left != nil { - yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t) + op1, _ := assignop(n1.Type(), t) + op2, _ := assignop(t, n1.Type()) + if op1 == ir.OXXX && op2 == ir.OXXX { + if n.Left() != nil { + base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left(), n1.Type(), t) } else { - yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type) + base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type()) } } } @@ -211,23 +215,23 @@ func typecheckExprSwitch(n *Node) { // case GOARCH == "arm" && GOARM == "5": // case GOARCH == "arm": // which would both evaluate to false for non-ARM compiles. - if !n1.Type.IsBoolean() { - cs.add(ncase.Pos, n1, "case", "switch") + if !n1.Type().IsBoolean() { + cs.add(ncase.Pos(), n1, "case", "switch") } } - typecheckslice(ncase.Nbody.Slice(), ctxStmt) + typecheckslice(ncase.Body().Slice(), ctxStmt) } } // walkswitch walks a switch statement. -func walkswitch(sw *Node) { +func walkswitch(sw ir.Node) { // Guard against double walk, see #25776. - if sw.List.Len() == 0 && sw.Nbody.Len() > 0 { + if sw.List().Len() == 0 && sw.Body().Len() > 0 { return // Was fatal, but eliminating every possible source of double-walking is hard } - if sw.Left != nil && sw.Left.Op == OTYPESW { + if sw.Left() != nil && sw.Left().Op() == ir.OTYPESW { walkTypeSwitch(sw) } else { walkExprSwitch(sw) @@ -236,11 +240,11 @@ func walkswitch(sw *Node) { // walkExprSwitch generates an AST implementing sw. sw is an // expression switch. -func walkExprSwitch(sw *Node) { +func walkExprSwitch(sw ir.Node) { lno := setlineno(sw) - cond := sw.Left - sw.Left = nil + cond := sw.Left() + sw.SetLeft(nil) // convert switch {...} to switch true {...} if cond == nil { @@ -256,79 +260,79 @@ func walkExprSwitch(sw *Node) { // because walkexpr will lower the string // conversion into a runtime call. // See issue 24937 for more discussion. - if cond.Op == OBYTES2STR && allCaseExprsAreSideEffectFree(sw) { - cond.Op = OBYTES2STRTMP + if cond.Op() == ir.OBYTES2STR && allCaseExprsAreSideEffectFree(sw) { + cond.SetOp(ir.OBYTES2STRTMP) } - cond = walkexpr(cond, &sw.Ninit) - if cond.Op != OLITERAL { - cond = copyexpr(cond, cond.Type, &sw.Nbody) + cond = walkexpr(cond, sw.PtrInit()) + if cond.Op() != ir.OLITERAL && cond.Op() != ir.ONIL { + cond = copyexpr(cond, cond.Type(), sw.PtrBody()) } - lineno = lno + base.Pos = lno s := exprSwitch{ exprname: cond, } - var defaultGoto *Node - var body Nodes - for _, ncase := range sw.List.Slice() { + var defaultGoto ir.Node + var body ir.Nodes + for _, ncase := range sw.List().Slice() { label := autolabel(".s") - jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label)) + jmp := npos(ncase.Pos(), nodSym(ir.OGOTO, nil, label)) // Process case dispatch. - if ncase.List.Len() == 0 { + if ncase.List().Len() == 0 { if defaultGoto != nil { - Fatalf("duplicate default case not detected during typechecking") + base.Fatalf("duplicate default case not detected during typechecking") } defaultGoto = jmp } - for _, n1 := range ncase.List.Slice() { - s.Add(ncase.Pos, n1, jmp) + for _, n1 := range ncase.List().Slice() { + s.Add(ncase.Pos(), n1, jmp) } // Process body. - body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label))) - body.Append(ncase.Nbody.Slice()...) - if fall, pos := hasFall(ncase.Nbody.Slice()); !fall { - br := nod(OBREAK, nil, nil) - br.Pos = pos + body.Append(npos(ncase.Pos(), nodSym(ir.OLABEL, nil, label))) + body.Append(ncase.Body().Slice()...) + if fall, pos := hasFall(ncase.Body().Slice()); !fall { + br := ir.Nod(ir.OBREAK, nil, nil) + br.SetPos(pos) body.Append(br) } } - sw.List.Set(nil) + sw.PtrList().Set(nil) if defaultGoto == nil { - br := nod(OBREAK, nil, nil) - br.Pos = br.Pos.WithNotStmt() + br := ir.Nod(ir.OBREAK, nil, nil) + br.SetPos(br.Pos().WithNotStmt()) defaultGoto = br } - s.Emit(&sw.Nbody) - sw.Nbody.Append(defaultGoto) - sw.Nbody.AppendNodes(&body) - walkstmtlist(sw.Nbody.Slice()) + s.Emit(sw.PtrBody()) + sw.PtrBody().Append(defaultGoto) + sw.PtrBody().AppendNodes(&body) + walkstmtlist(sw.Body().Slice()) } // An exprSwitch walks an expression switch. type exprSwitch struct { - exprname *Node // value being switched on + exprname ir.Node // value being switched on - done Nodes + done ir.Nodes clauses []exprClause } type exprClause struct { pos src.XPos - lo, hi *Node - jmp *Node + lo, hi ir.Node + jmp ir.Node } -func (s *exprSwitch) Add(pos src.XPos, expr, jmp *Node) { +func (s *exprSwitch) Add(pos src.XPos, expr, jmp ir.Node) { c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp} - if okforcmp[s.exprname.Type.Etype] && expr.Op == OLITERAL { + if okforcmp[s.exprname.Type().Etype] && expr.Op() == ir.OLITERAL { s.clauses = append(s.clauses, c) return } @@ -338,7 +342,7 @@ func (s *exprSwitch) Add(pos src.XPos, expr, jmp *Node) { s.flush() } -func (s *exprSwitch) Emit(out *Nodes) { +func (s *exprSwitch) Emit(out *ir.Nodes) { s.flush() out.AppendNodes(&s.done) } @@ -355,7 +359,7 @@ func (s *exprSwitch) flush() { // (e.g., sort.Slice doesn't need to invoke the less function // when there's only a single slice element). - if s.exprname.Type.IsString() && len(cc) >= 2 { + if s.exprname.Type().IsString() && len(cc) >= 2 { // Sort strings by length and then by value. It is // much cheaper to compare lengths than values, and // all we need here is consistency. We respect this @@ -385,26 +389,25 @@ func (s *exprSwitch) flush() { runs = append(runs, cc[start:]) // Perform two-level binary search. - nlen := nod(OLEN, s.exprname, nil) binarySearch(len(runs), &s.done, - func(i int) *Node { - return nod(OLE, nlen, nodintconst(runLen(runs[i-1]))) + func(i int) ir.Node { + return ir.Nod(ir.OLE, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1]))) }, - func(i int, nif *Node) { + func(i int, nif ir.Node) { run := runs[i] - nif.Left = nod(OEQ, nlen, nodintconst(runLen(run))) - s.search(run, &nif.Nbody) + nif.SetLeft(ir.Nod(ir.OEQ, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(run)))) + s.search(run, nif.PtrBody()) }, ) return } sort.Slice(cc, func(i, j int) bool { - return compareOp(cc[i].lo.Val(), OLT, cc[j].lo.Val()) + return constant.Compare(cc[i].lo.Val(), token.LSS, cc[j].lo.Val()) }) // Merge consecutive integer cases. - if s.exprname.Type.IsInteger() { + if s.exprname.Type().IsInteger() { merged := cc[:1] for _, c := range cc[1:] { last := &merged[len(merged)-1] @@ -420,40 +423,40 @@ func (s *exprSwitch) flush() { s.search(cc, &s.done) } -func (s *exprSwitch) search(cc []exprClause, out *Nodes) { +func (s *exprSwitch) search(cc []exprClause, out *ir.Nodes) { binarySearch(len(cc), out, - func(i int) *Node { - return nod(OLE, s.exprname, cc[i-1].hi) + func(i int) ir.Node { + return ir.Nod(ir.OLE, s.exprname, cc[i-1].hi) }, - func(i int, nif *Node) { + func(i int, nif ir.Node) { c := &cc[i] - nif.Left = c.test(s.exprname) - nif.Nbody.Set1(c.jmp) + nif.SetLeft(c.test(s.exprname)) + nif.PtrBody().Set1(c.jmp) }, ) } -func (c *exprClause) test(exprname *Node) *Node { +func (c *exprClause) test(exprname ir.Node) ir.Node { // Integer range. if c.hi != c.lo { - low := nodl(c.pos, OGE, exprname, c.lo) - high := nodl(c.pos, OLE, exprname, c.hi) - return nodl(c.pos, OANDAND, low, high) + low := ir.NodAt(c.pos, ir.OGE, exprname, c.lo) + high := ir.NodAt(c.pos, ir.OLE, exprname, c.hi) + return ir.NodAt(c.pos, ir.OANDAND, low, high) } // Optimize "switch true { ...}" and "switch false { ... }". - if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() { + if ir.IsConst(exprname, constant.Bool) && !c.lo.Type().IsInterface() { if exprname.BoolVal() { return c.lo } else { - return nodl(c.pos, ONOT, c.lo, nil) + return ir.NodAt(c.pos, ir.ONOT, c.lo, nil) } } - return nodl(c.pos, OEQ, exprname, c.lo) + return ir.NodAt(c.pos, ir.OEQ, exprname, c.lo) } -func allCaseExprsAreSideEffectFree(sw *Node) bool { +func allCaseExprsAreSideEffectFree(sw ir.Node) bool { // In theory, we could be more aggressive, allowing any // side-effect-free expressions in cases, but it's a bit // tricky because some of that information is unavailable due @@ -461,12 +464,12 @@ func allCaseExprsAreSideEffectFree(sw *Node) bool { // Restricting to constants is simple and probably powerful // enough. - for _, ncase := range sw.List.Slice() { - if ncase.Op != OCASE { - Fatalf("switch string(byteslice) bad op: %v", ncase.Op) + for _, ncase := range sw.List().Slice() { + if ncase.Op() != ir.OCASE { + base.Fatalf("switch string(byteslice) bad op: %v", ncase.Op()) } - for _, v := range ncase.List.Slice() { - if v.Op != OLITERAL { + for _, v := range ncase.List().Slice() { + if v.Op() != ir.OLITERAL { return false } } @@ -475,7 +478,7 @@ func allCaseExprsAreSideEffectFree(sw *Node) bool { } // hasFall reports whether stmts ends with a "fallthrough" statement. -func hasFall(stmts []*Node) (bool, src.XPos) { +func hasFall(stmts []ir.Node) (bool, src.XPos) { // Search backwards for the index of the fallthrough // statement. Do not assume it'll be in the last // position, since in some cases (e.g. when the statement @@ -483,30 +486,30 @@ func hasFall(stmts []*Node) (bool, src.XPos) { // nodes will be at the end of the list. i := len(stmts) - 1 - for i >= 0 && stmts[i].Op == OVARKILL { + for i >= 0 && stmts[i].Op() == ir.OVARKILL { i-- } if i < 0 { return false, src.NoXPos } - return stmts[i].Op == OFALL, stmts[i].Pos + return stmts[i].Op() == ir.OFALL, stmts[i].Pos() } // walkTypeSwitch generates an AST that implements sw, where sw is a // type switch. -func walkTypeSwitch(sw *Node) { +func walkTypeSwitch(sw ir.Node) { var s typeSwitch - s.facename = sw.Left.Right - sw.Left = nil + s.facename = sw.Left().Right() + sw.SetLeft(nil) - s.facename = walkexpr(s.facename, &sw.Ninit) - s.facename = copyexpr(s.facename, s.facename.Type, &sw.Nbody) - s.okname = temp(types.Types[TBOOL]) + s.facename = walkexpr(s.facename, sw.PtrInit()) + s.facename = copyexpr(s.facename, s.facename.Type(), sw.PtrBody()) + s.okname = temp(types.Types[types.TBOOL]) // Get interface descriptor word. // For empty interfaces this will be the type. // For non-empty interfaces this will be the itab. - itab := nod(OITAB, s.facename, nil) + itab := ir.Nod(ir.OITAB, s.facename, nil) // For empty interfaces, do: // if e._type == nil { @@ -514,92 +517,92 @@ func walkTypeSwitch(sw *Node) { // } // h := e._type.hash // Use a similar strategy for non-empty interfaces. - ifNil := nod(OIF, nil, nil) - ifNil.Left = nod(OEQ, itab, nodnil()) - lineno = lineno.WithNotStmt() // disable statement marks after the first check. - ifNil.Left = typecheck(ifNil.Left, ctxExpr) - ifNil.Left = defaultlit(ifNil.Left, nil) + ifNil := ir.Nod(ir.OIF, nil, nil) + ifNil.SetLeft(ir.Nod(ir.OEQ, itab, nodnil())) + base.Pos = base.Pos.WithNotStmt() // disable statement marks after the first check. + ifNil.SetLeft(typecheck(ifNil.Left(), ctxExpr)) + ifNil.SetLeft(defaultlit(ifNil.Left(), nil)) // ifNil.Nbody assigned at end. - sw.Nbody.Append(ifNil) + sw.PtrBody().Append(ifNil) // Load hash from type or itab. - dotHash := nodSym(ODOTPTR, itab, nil) - dotHash.Type = types.Types[TUINT32] + dotHash := nodSym(ir.ODOTPTR, itab, nil) + dotHash.SetType(types.Types[types.TUINT32]) dotHash.SetTypecheck(1) - if s.facename.Type.IsEmptyInterface() { - dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type + if s.facename.Type().IsEmptyInterface() { + dotHash.SetOffset(int64(2 * Widthptr)) // offset of hash in runtime._type } else { - dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime.itab + dotHash.SetOffset(int64(2 * Widthptr)) // offset of hash in runtime.itab } dotHash.SetBounded(true) // guaranteed not to fault - s.hashname = copyexpr(dotHash, dotHash.Type, &sw.Nbody) - - br := nod(OBREAK, nil, nil) - var defaultGoto, nilGoto *Node - var body Nodes - for _, ncase := range sw.List.Slice() { - var caseVar *Node - if ncase.Rlist.Len() != 0 { - caseVar = ncase.Rlist.First() + s.hashname = copyexpr(dotHash, dotHash.Type(), sw.PtrBody()) + + br := ir.Nod(ir.OBREAK, nil, nil) + var defaultGoto, nilGoto ir.Node + var body ir.Nodes + for _, ncase := range sw.List().Slice() { + var caseVar ir.Node + if ncase.Rlist().Len() != 0 { + caseVar = ncase.Rlist().First() } // For single-type cases with an interface type, // we initialize the case variable as part of the type assertion. // In other cases, we initialize it in the body. var singleType *types.Type - if ncase.List.Len() == 1 && ncase.List.First().Op == OTYPE { - singleType = ncase.List.First().Type + if ncase.List().Len() == 1 && ncase.List().First().Op() == ir.OTYPE { + singleType = ncase.List().First().Type() } caseVarInitialized := false label := autolabel(".s") - jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label)) + jmp := npos(ncase.Pos(), nodSym(ir.OGOTO, nil, label)) - if ncase.List.Len() == 0 { // default: + if ncase.List().Len() == 0 { // default: if defaultGoto != nil { - Fatalf("duplicate default case not detected during typechecking") + base.Fatalf("duplicate default case not detected during typechecking") } defaultGoto = jmp } - for _, n1 := range ncase.List.Slice() { - if n1.isNil() { // case nil: + for _, n1 := range ncase.List().Slice() { + if ir.IsNil(n1) { // case nil: if nilGoto != nil { - Fatalf("duplicate nil case not detected during typechecking") + base.Fatalf("duplicate nil case not detected during typechecking") } nilGoto = jmp continue } if singleType != nil && singleType.IsInterface() { - s.Add(ncase.Pos, n1.Type, caseVar, jmp) + s.Add(ncase.Pos(), n1.Type(), caseVar, jmp) caseVarInitialized = true } else { - s.Add(ncase.Pos, n1.Type, nil, jmp) + s.Add(ncase.Pos(), n1.Type(), nil, jmp) } } - body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label))) + body.Append(npos(ncase.Pos(), nodSym(ir.OLABEL, nil, label))) if caseVar != nil && !caseVarInitialized { val := s.facename if singleType != nil { // We have a single concrete type. Extract the data. if singleType.IsInterface() { - Fatalf("singleType interface should have been handled in Add") + base.Fatalf("singleType interface should have been handled in Add") } - val = ifaceData(ncase.Pos, s.facename, singleType) + val = ifaceData(ncase.Pos(), s.facename, singleType) } - l := []*Node{ - nodl(ncase.Pos, ODCL, caseVar, nil), - nodl(ncase.Pos, OAS, caseVar, val), + l := []ir.Node{ + ir.NodAt(ncase.Pos(), ir.ODCL, caseVar, nil), + ir.NodAt(ncase.Pos(), ir.OAS, caseVar, val), } typecheckslice(l, ctxStmt) body.Append(l...) } - body.Append(ncase.Nbody.Slice()...) + body.Append(ncase.Body().Slice()...) body.Append(br) } - sw.List.Set(nil) + sw.PtrList().Set(nil) if defaultGoto == nil { defaultGoto = br @@ -607,58 +610,58 @@ func walkTypeSwitch(sw *Node) { if nilGoto == nil { nilGoto = defaultGoto } - ifNil.Nbody.Set1(nilGoto) + ifNil.PtrBody().Set1(nilGoto) - s.Emit(&sw.Nbody) - sw.Nbody.Append(defaultGoto) - sw.Nbody.AppendNodes(&body) + s.Emit(sw.PtrBody()) + sw.PtrBody().Append(defaultGoto) + sw.PtrBody().AppendNodes(&body) - walkstmtlist(sw.Nbody.Slice()) + walkstmtlist(sw.Body().Slice()) } // A typeSwitch walks a type switch. type typeSwitch struct { // Temporary variables (i.e., ONAMEs) used by type switch dispatch logic: - facename *Node // value being type-switched on - hashname *Node // type hash of the value being type-switched on - okname *Node // boolean used for comma-ok type assertions + facename ir.Node // value being type-switched on + hashname ir.Node // type hash of the value being type-switched on + okname ir.Node // boolean used for comma-ok type assertions - done Nodes + done ir.Nodes clauses []typeClause } type typeClause struct { hash uint32 - body Nodes + body ir.Nodes } -func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) { - var body Nodes +func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp ir.Node) { + var body ir.Nodes if caseVar != nil { - l := []*Node{ - nodl(pos, ODCL, caseVar, nil), - nodl(pos, OAS, caseVar, nil), + l := []ir.Node{ + ir.NodAt(pos, ir.ODCL, caseVar, nil), + ir.NodAt(pos, ir.OAS, caseVar, nil), } typecheckslice(l, ctxStmt) body.Append(l...) } else { - caseVar = nblank + caseVar = ir.BlankNode } // cv, ok = iface.(type) - as := nodl(pos, OAS2, nil, nil) - as.List.Set2(caseVar, s.okname) // cv, ok = - dot := nodl(pos, ODOTTYPE, s.facename, nil) - dot.Type = typ // iface.(type) - as.Rlist.Set1(dot) + as := ir.NodAt(pos, ir.OAS2, nil, nil) + as.PtrList().Set2(caseVar, s.okname) // cv, ok = + dot := ir.NodAt(pos, ir.ODOTTYPE, s.facename, nil) + dot.SetType(typ) // iface.(type) + as.PtrRlist().Set1(dot) as = typecheck(as, ctxStmt) as = walkexpr(as, &body) body.Append(as) // if ok { goto label } - nif := nodl(pos, OIF, nil, nil) - nif.Left = s.okname - nif.Nbody.Set1(jmp) + nif := ir.NodAt(pos, ir.OIF, nil, nil) + nif.SetLeft(s.okname) + nif.PtrBody().Set1(jmp) body.Append(nif) if !typ.IsInterface() { @@ -673,7 +676,7 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) { s.done.AppendNodes(&body) } -func (s *typeSwitch) Emit(out *Nodes) { +func (s *typeSwitch) Emit(out *ir.Nodes) { s.flush() out.AppendNodes(&s.done) } @@ -700,15 +703,15 @@ func (s *typeSwitch) flush() { cc = merged binarySearch(len(cc), &s.done, - func(i int) *Node { - return nod(OLE, s.hashname, nodintconst(int64(cc[i-1].hash))) + func(i int) ir.Node { + return ir.Nod(ir.OLE, s.hashname, nodintconst(int64(cc[i-1].hash))) }, - func(i int, nif *Node) { + func(i int, nif ir.Node) { // TODO(mdempsky): Omit hash equality check if // there's only one type. c := cc[i] - nif.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash))) - nif.Nbody.AppendNodes(&c.body) + nif.SetLeft(ir.Nod(ir.OEQ, s.hashname, nodintconst(int64(c.hash)))) + nif.PtrBody().AppendNodes(&c.body) }, ) } @@ -720,35 +723,35 @@ func (s *typeSwitch) flush() { // less(i) should return a boolean expression. If it evaluates true, // then cases before i will be tested; otherwise, cases i and later. // -// base(i, nif) should setup nif (an OIF node) to test case i. In +// leaf(i, nif) should setup nif (an OIF node) to test case i. In // particular, it should set nif.Left and nif.Nbody. -func binarySearch(n int, out *Nodes, less func(i int) *Node, base func(i int, nif *Node)) { +func binarySearch(n int, out *ir.Nodes, less func(i int) ir.Node, leaf func(i int, nif ir.Node)) { const binarySearchMin = 4 // minimum number of cases for binary search - var do func(lo, hi int, out *Nodes) - do = func(lo, hi int, out *Nodes) { + var do func(lo, hi int, out *ir.Nodes) + do = func(lo, hi int, out *ir.Nodes) { n := hi - lo if n < binarySearchMin { for i := lo; i < hi; i++ { - nif := nod(OIF, nil, nil) - base(i, nif) - lineno = lineno.WithNotStmt() - nif.Left = typecheck(nif.Left, ctxExpr) - nif.Left = defaultlit(nif.Left, nil) + nif := ir.Nod(ir.OIF, nil, nil) + leaf(i, nif) + base.Pos = base.Pos.WithNotStmt() + nif.SetLeft(typecheck(nif.Left(), ctxExpr)) + nif.SetLeft(defaultlit(nif.Left(), nil)) out.Append(nif) - out = &nif.Rlist + out = nif.PtrRlist() } return } half := lo + n/2 - nif := nod(OIF, nil, nil) - nif.Left = less(half) - lineno = lineno.WithNotStmt() - nif.Left = typecheck(nif.Left, ctxExpr) - nif.Left = defaultlit(nif.Left, nil) - do(lo, half, &nif.Nbody) - do(half, hi, &nif.Rlist) + nif := ir.Nod(ir.OIF, nil, nil) + nif.SetLeft(less(half)) + base.Pos = base.Pos.WithNotStmt() + nif.SetLeft(typecheck(nif.Left(), ctxExpr)) + nif.SetLeft(defaultlit(nif.Left(), nil)) + do(lo, half, nif.PtrBody()) + do(half, hi, nif.PtrRlist()) out.Append(nif) } |