typecheckFunc(fn)
 
        Curfn = fn
-       typecheckslice(fn.Body.Slice(), ctxStmt)
+       typecheckslice(fn.Body, ctxStmt)
        Curfn = nil
 
        if base.Debug.DclStack != 0 {
        typecheckFunc(fn)
 
        Curfn = fn
-       typecheckslice(fn.Body.Slice(), ctxStmt)
+       typecheckslice(fn.Body, ctxStmt)
        Curfn = nil
 
        if base.Debug.DclStack != 0 {
 
                Curfn = fn
                olddd := decldepth
                decldepth = 1
-               typecheckslice(fn.Body.Slice(), ctxStmt)
+               typecheckslice(fn.Body, ctxStmt)
                decldepth = olddd
                Curfn = oldfn
        }
 
        clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
        clos.SetEsc(clo.Esc())
-       clos.List.Set(append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, fn.Nname)}, fn.ClosureEnter.Slice()...))
+       clos.List.Set(append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, fn.Nname)}, fn.ClosureEnter...))
 
        addr := nodAddr(clos)
        addr.SetEsc(clo.Esc())
        call.IsDDD = tfn.Type().IsVariadic()
        if t0.NumResults() != 0 {
                ret := ir.NewReturnStmt(base.Pos, nil)
-               ret.Results.Set1(call)
+               ret.Results = []ir.Node{call}
                body = append(body, ret)
        } else {
                body = append(body, call)
        // Need to typecheck the body of the just-generated wrapper.
        // typecheckslice() requires that Curfn is set when processing an ORETURN.
        Curfn = fn
-       typecheckslice(fn.Body.Slice(), ctxStmt)
+       typecheckslice(fn.Body, ctxStmt)
        sym.Def = fn
        Target.Decls = append(Target.Decls, fn)
        Curfn = savecurfn
 
        clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
        clos.SetEsc(n.Esc())
-       clos.List.Set2(ir.NewUnaryExpr(base.Pos, ir.OCFUNC, n.Func.Nname), n.X)
+       clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, n.Func.Nname), n.X}
 
        addr := nodAddr(clos)
        addr.SetEsc(n.Esc())
 
        case ir.OADDSTR:
                // Merge adjacent constants in the argument list.
                n := n.(*ir.AddStringExpr)
-               s := n.List.Slice()
+               s := n.List
                need := 0
                for i := 0; i < len(s); i++ {
                        if i == 0 || !ir.IsConst(s[i-1], constant.String) || !ir.IsConst(s[i], constant.String) {
 
        if len(el) == 1 && len(vl) > 1 {
                e := el[0]
                as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-               as2.Rhs.Set1(e)
+               as2.Rhs = []ir.Node{e}
                for _, v := range vl {
                        as2.Lhs.Append(v)
                        declare(v, dclcontext)
        }
 
        var callee *ir.Func
-       arg := n.Args.First()
+       arg := n.Args[0]
        switch arg.Op() {
        case ir.ONAME:
                arg := arg.(*ir.Name)
 
                typesw := n.Tag != nil && n.Tag.Op() == ir.OTYPESW
 
                var ks []EscHole
-               for _, cas := range n.Cases.Slice() { // cases
+               for _, cas := range n.Cases { // cases
                        cas := cas.(*ir.CaseStmt)
                        if typesw && n.Tag.(*ir.TypeSwitchGuard).Tag != nil {
-                               cv := cas.Vars.First()
+                               cv := cas.Vars[0]
                                k := e.dcl(cv) // type switch variables have no ODCL.
                                if cv.Type().HasPointers() {
                                        ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
 
        case ir.OSELECT:
                n := n.(*ir.SelectStmt)
-               for _, cas := range n.Cases.Slice() {
+               for _, cas := range n.Cases {
                        cas := cas.(*ir.CaseStmt)
                        e.stmt(cas.Comm)
                        e.block(cas.Body)
                }
        case ir.OSELRECV2:
                n := n.(*ir.AssignListStmt)
-               e.assign(n.Lhs.First(), n.Rhs.First(), "selrecv", n)
-               e.assign(n.Lhs.Second(), nil, "selrecv", n)
+               e.assign(n.Lhs[0], n.Rhs[0], "selrecv", n)
+               e.assign(n.Lhs[1], nil, "selrecv", n)
        case ir.ORECV:
                // TODO(mdempsky): Consider e.discard(n.Left).
                n := n.(*ir.UnaryExpr)
                e.assign(n.X, n.Y, "assign", n)
        case ir.OAS2:
                n := n.(*ir.AssignListStmt)
-               for i, nl := range n.Lhs.Slice() {
-                       e.assign(nl, n.Rhs.Index(i), "assign-pair", n)
+               for i, nl := range n.Lhs {
+                       e.assign(nl, n.Rhs[i], "assign-pair", n)
                }
 
        case ir.OAS2DOTTYPE: // v, ok = x.(type)
                n := n.(*ir.AssignListStmt)
-               e.assign(n.Lhs.First(), n.Rhs.First(), "assign-pair-dot-type", n)
-               e.assign(n.Lhs.Second(), nil, "assign-pair-dot-type", n)
+               e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-dot-type", n)
+               e.assign(n.Lhs[1], nil, "assign-pair-dot-type", n)
        case ir.OAS2MAPR: // v, ok = m[k]
                n := n.(*ir.AssignListStmt)
-               e.assign(n.Lhs.First(), n.Rhs.First(), "assign-pair-mapr", n)
-               e.assign(n.Lhs.Second(), nil, "assign-pair-mapr", n)
+               e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-mapr", n)
+               e.assign(n.Lhs[1], nil, "assign-pair-mapr", n)
        case ir.OAS2RECV: // v, ok = <-ch
                n := n.(*ir.AssignListStmt)
-               e.assign(n.Lhs.First(), n.Rhs.First(), "assign-pair-receive", n)
-               e.assign(n.Lhs.Second(), nil, "assign-pair-receive", n)
+               e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-receive", n)
+               e.assign(n.Lhs[1], nil, "assign-pair-receive", n)
 
        case ir.OAS2FUNC:
                n := n.(*ir.AssignListStmt)
-               e.stmts(n.Rhs.First().Init())
-               e.call(e.addrs(n.Lhs), n.Rhs.First(), nil)
+               e.stmts(n.Rhs[0].Init())
+               e.call(e.addrs(n.Lhs), n.Rhs[0], nil)
        case ir.ORETURN:
                n := n.(*ir.ReturnStmt)
                results := e.curfn.Type().Results().FieldSlice()
-               for i, v := range n.Results.Slice() {
+               for i, v := range n.Results {
                        e.assign(ir.AsNode(results[i].Nname), v, "return", n)
                }
        case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
 }
 
 func (e *Escape) stmts(l ir.Nodes) {
-       for _, n := range l.Slice() {
+       for _, n := range l {
                e.stmt(n)
        }
 }
 
        case ir.OARRAYLIT:
                n := n.(*ir.CompLitExpr)
-               for _, elt := range n.List.Slice() {
+               for _, elt := range n.List {
                        if elt.Op() == ir.OKEY {
                                elt = elt.(*ir.KeyExpr).Value
                        }
                k = e.spill(k, n)
                k.uintptrEscapesHack = uintptrEscapesHack // for ...uintptr parameters
 
-               for _, elt := range n.List.Slice() {
+               for _, elt := range n.List {
                        if elt.Op() == ir.OKEY {
                                elt = elt.(*ir.KeyExpr).Value
                        }
 
        case ir.OSTRUCTLIT:
                n := n.(*ir.CompLitExpr)
-               for _, elt := range n.List.Slice() {
+               for _, elt := range n.List {
                        e.expr(k.note(n, "struct literal element"), elt.(*ir.StructKeyExpr).Value)
                }
 
                e.spill(k, n)
 
                // Map keys and values are always stored in the heap.
-               for _, elt := range n.List.Slice() {
+               for _, elt := range n.List {
                        elt := elt.(*ir.KeyExpr)
                        e.assignHeap(elt.Key, "map literal key", n)
                        e.assignHeap(elt.Value, "map literal value", n)
 }
 
 func (e *Escape) discards(l ir.Nodes) {
-       for _, n := range l.Slice() {
+       for _, n := range l {
                e.discard(n)
        }
 }
 
 func (e *Escape) addrs(l ir.Nodes) []EscHole {
        var ks []EscHole
-       for _, n := range l.Slice() {
+       for _, n := range l {
                ks = append(ks, e.addr(n))
        }
        return ks
                        argument(e.discardHole(), call.X)
                }
 
-               args := call.Args.Slice()
+               args := call.Args
                for i, param := range fntype.Params().FieldSlice() {
                        argument(e.tagHole(ks, fn, param), args[i])
                }
 
        case ir.OAPPEND:
                call := call.(*ir.CallExpr)
-               args := call.Args.Slice()
+               args := call.Args
 
                // Appendee slice may flow directly to the result, if
                // it has enough capacity. Alternatively, a new heap
                argument(e.discardHole(), call.Y)
        case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
                call := call.(*ir.CallExpr)
-               for _, arg := range call.Args.Slice() {
+               for _, arg := range call.Args {
                        argument(e.discardHole(), arg)
                }
        case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
                return fmt.Sprintf("arg#%d", narg)
        }
 
-       if fn.Body.Len() == 0 {
+       if len(fn.Body) == 0 {
                // Assume that uintptr arguments must be held live across the call.
                // This is most important for syscall.Syscall.
                // See golang.org/issue/13372.
 
                tail = call
                if tfn.Type().NumResults() > 0 {
                        n := ir.NewReturnStmt(base.Pos, nil)
-                       n.Results.Set1(call)
+                       n.Results = []ir.Node{call}
                        tail = n
                }
        }
 
        typecheckFunc(fn)
        Curfn = fn
-       typecheckslice(fn.Body.Slice(), ctxStmt)
+       typecheckslice(fn.Body, ctxStmt)
 
        escapeFuncs([]*ir.Func{fn}, false)
 
 
        w := p.newWriter()
        w.setPkg(fnpkg(f), false)
 
-       w.stmtList(ir.AsNodes(f.Func.Inl.Body))
+       w.stmtList(ir.Nodes(f.Func.Inl.Body))
 
        w.finish("inl", p.inlineIndex, f.Sym())
 }
 // Inline bodies.
 
 func (w *exportWriter) stmtList(list ir.Nodes) {
-       for _, n := range list.Slice() {
+       for _, n := range list {
                w.node(n)
        }
        w.op(ir.OEND)
 // Caution: stmt will emit more than one node for statement nodes n that have a non-empty
 // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
 func (w *exportWriter) stmt(n ir.Node) {
-       if n.Init().Len() > 0 && !ir.StmtWithInit(n.Op()) {
+       if len(n.Init()) > 0 && !ir.StmtWithInit(n.Op()) {
                // can't use stmtList here since we don't want the final OEND
-               for _, n := range n.Init().Slice() {
+               for _, n := range n.Init() {
                        w.stmt(n)
                }
        }
                // generate OBLOCK nodes except to denote an empty
                // function body, although that may change.)
                n := n.(*ir.BlockStmt)
-               for _, n := range n.List.Slice() {
+               for _, n := range n.List {
                        w.stmt(n)
                }
 
 
        var cases []ir.Node
        if sw.Op() == ir.OSWITCH {
-               cases = sw.(*ir.SwitchStmt).Cases.Slice()
+               cases = sw.(*ir.SwitchStmt).Cases
        } else {
-               cases = sw.(*ir.SelectStmt).Cases.Slice()
+               cases = sw.(*ir.SelectStmt).Cases
        }
        w.uint64(uint64(len(cases)))
        for _, cas := range cases {
                w.pos(cas.Pos())
                w.stmtList(cas.List)
                if namedTypeSwitch {
-                       w.localName(cas.Vars.First().(*ir.Name))
+                       w.localName(cas.Vars[0].(*ir.Name))
                }
                w.stmtList(cas.Body)
        }
 }
 
 func (w *exportWriter) exprList(list ir.Nodes) {
-       for _, n := range list.Slice() {
+       for _, n := range list {
                w.expr(n)
        }
        w.op(ir.OEND)
 }
 
 func (w *exportWriter) fieldList(list ir.Nodes) {
-       w.uint64(uint64(list.Len()))
-       for _, n := range list.Slice() {
+       w.uint64(uint64(len(list)))
+       for _, n := range list {
                n := n.(*ir.StructKeyExpr)
                w.selector(n.Field)
                w.expr(n.Value)
 
 
        if base.Flag.E > 0 && base.Flag.LowerM > 2 {
                if base.Flag.LowerM > 3 {
-                       fmt.Printf("inl body for %v %v: %+v\n", fn, fn.Type(), ir.AsNodes(fn.Inl.Body))
+                       fmt.Printf("inl body for %v %v: %+v\n", fn, fn.Type(), ir.Nodes(fn.Inl.Body))
                } else {
-                       fmt.Printf("inl body for %v %v: %v\n", fn, fn.Type(), ir.AsNodes(fn.Inl.Body))
+                       fmt.Printf("inl body for %v %v: %v\n", fn, fn.Type(), ir.Nodes(fn.Inl.Body))
                }
        }
 }
                // Inline them into the statement list.
                if n.Op() == ir.OBLOCK {
                        n := n.(*ir.BlockStmt)
-                       list = append(list, n.List.Slice()...)
+                       list = append(list, n.List...)
                } else {
                        list = append(list, n)
                }
                        // Sym for diagnostics anyway.
                        caseVar := ir.NewNameAt(cas.Pos(), r.ident())
                        declare(caseVar, dclcontext)
-                       cas.Vars.Set1(caseVar)
+                       cas.Vars = []ir.Node{caseVar}
                        caseVar.Defn = sw.(*ir.SwitchStmt).Tag
                }
                cas.Body.Set(r.stmtList())
                var stmts ir.Nodes
                stmts.Append(ir.NewDecl(base.Pos, ir.ODCL, lhs))
                stmts.Append(ir.NewAssignStmt(base.Pos, lhs, nil))
-               return ir.NewBlockStmt(pos, stmts.Slice())
+               return ir.NewBlockStmt(pos, stmts)
 
        // case OAS, OASWB:
        //      unreachable - mapped to OAS case below by exporter
 
        // Record user init functions.
        for _, fn := range Target.Inits {
                // Skip init functions with empty bodies.
-               if fn.Body.Len() == 1 {
-                       if stmt := fn.Body.First(); stmt.Op() == ir.OBLOCK && stmt.(*ir.BlockStmt).List.Len() == 0 {
+               if len(fn.Body) == 1 {
+                       if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
                                continue
                        }
                }
 
                d.inspect(n.Y)
        case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
                n := n.(*ir.AssignListStmt)
-               d.inspect(n.Rhs.First())
+               d.inspect(n.Rhs[0])
        case ir.ODCLFUNC:
                n := n.(*ir.Func)
                d.inspectList(n.Body)
                return n.X.Name()
        case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2RECV, ir.OAS2MAPR:
                n := n.(*ir.AssignListStmt)
-               return n.Lhs.First().Name()
+               return n.Lhs[0].Name()
        }
 
        base.Fatalf("unexpected Op: %v", n.Op())
 
        }
 
        if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
-               fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.AsNodes(fn.Inl.Body))
+               fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
        }
 
        savefn := Curfn
        }
 
        // If fn has no body (is defined outside of Go), cannot inline it.
-       if fn.Body.Len() == 0 {
+       if len(fn.Body) == 0 {
                reason = "no function body"
                return
        }
        n.Func.Inl = &ir.Inline{
                Cost: inlineMaxBudget - visitor.budget,
                Dcl:  pruneUnusedAutos(n.Defn.(*ir.Func).Dcl, &visitor),
-               Body: ir.DeepCopyList(src.NoXPos, fn.Body.Slice()),
+               Body: ir.DeepCopyList(src.NoXPos, fn.Body),
        }
 
        if base.Flag.LowerM > 1 {
-               fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, inlineMaxBudget-visitor.budget, fn.Type(), ir.AsNodes(n.Func.Inl.Body))
+               fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, inlineMaxBudget-visitor.budget, fn.Type(), ir.Nodes(n.Func.Inl.Body))
        } else if base.Flag.LowerM != 0 {
                fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
        }
        // Recursively identify all referenced functions for
        // reexport. We want to include even non-called functions,
        // because after inlining they might be callable.
-       ir.VisitList(ir.AsNodes(fn.Inl.Body), func(n ir.Node) {
+       ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
                switch n.Op() {
                case ir.OMETHEXPR, ir.ODOTMETH:
                        inlFlood(methodExprName(n), exportsym)
 func inlconv2stmt(inlcall *ir.InlinedCallExpr) ir.Node {
        n := ir.NewBlockStmt(inlcall.Pos(), nil)
        n.List = inlcall.Init()
-       n.List.AppendNodes(&inlcall.Body)
+       n.List.Append(inlcall.Body.Take()...)
        return n
 }
 
 // The result of inlconv2expr MUST be assigned back to n, e.g.
 //     n.Left = inlconv2expr(n.Left)
 func inlconv2expr(n *ir.InlinedCallExpr) ir.Node {
-       r := n.ReturnVars.First()
-       return initExpr(append(n.Init().Slice(), n.Body.Slice()...), r)
+       r := n.ReturnVars[0]
+       return initExpr(append(n.Init(), n.Body...), r)
 }
 
 // Turn the rlist (with the return values) of the OINLCALL in
 // order will be preserved. Used in return, oas2func and call
 // statements.
 func inlconv2list(n *ir.InlinedCallExpr) []ir.Node {
-       if n.Op() != ir.OINLCALL || n.ReturnVars.Len() == 0 {
+       if n.Op() != ir.OINLCALL || len(n.ReturnVars) == 0 {
                base.Fatalf("inlconv2list %+v\n", n)
        }
 
-       s := n.ReturnVars.Slice()
-       s[0] = initExpr(append(n.Init().Slice(), n.Body.Slice()...), s[0])
+       s := n.ReturnVars
+       s[0] = initExpr(append(n.Init(), n.Body...), s[0])
        return s
 }
 
 
        if as := n; as.Op() == ir.OAS2FUNC {
                as := as.(*ir.AssignListStmt)
-               if as.Rhs.First().Op() == ir.OINLCALL {
-                       as.Rhs.Set(inlconv2list(as.Rhs.First().(*ir.InlinedCallExpr)))
+               if as.Rhs[0].Op() == ir.OINLCALL {
+                       as.Rhs.Set(inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr)))
                        as.SetOp(ir.OAS2)
                        as.SetTypecheck(0)
                        n = typecheck(as, ctxStmt)
                rhs = defn.Y
        case ir.OAS2:
                defn := defn.(*ir.AssignListStmt)
-               for i, lhs := range defn.Lhs.Slice() {
+               for i, lhs := range defn.Lhs {
                        if lhs == n {
-                               rhs = defn.Rhs.Index(i)
+                               rhs = defn.Rhs[i]
                                break FindRHS
                        }
                }
                        }
                case ir.OAS2, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OSELRECV2:
                        n := n.(*ir.AssignListStmt)
-                       for _, p := range n.Lhs.Slice() {
+                       for _, p := range n.Lhs {
                                if p == name && n != name.Defn {
                                        return true
                                }
 
        // We have a function node, and it has an inlineable body.
        if base.Flag.LowerM > 1 {
-               fmt.Printf("%v: inlining call to %v %v { %v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.AsNodes(fn.Inl.Body))
+               fmt.Printf("%v: inlining call to %v %v { %v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.Nodes(fn.Inl.Body))
        } else if base.Flag.LowerM != 0 {
                fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
        }
                callee := n.X
                for callee.Op() == ir.OCONVNOP {
                        conv := callee.(*ir.ConvExpr)
-                       ninit.AppendNodes(conv.PtrInit())
+                       ninit.Append(conv.PtrInit().Take()...)
                        callee = conv.X
                }
                if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
        }
 
        nreturns := 0
-       ir.VisitList(ir.AsNodes(fn.Inl.Body), func(n ir.Node) {
+       ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
                if n != nil && n.Op() == ir.ORETURN {
                        nreturns++
                }
                }
                as.Rhs.Append(sel.X)
        }
-       as.Rhs.Append(n.Args.Slice()...)
+       as.Rhs.Append(n.Args...)
 
        // For non-dotted calls to variadic functions, we assign the
        // variadic parameter's temp name separately.
                // Otherwise, we need to collect the remaining values
                // to pass as a slice.
 
-               x := as.Lhs.Len()
-               for as.Lhs.Len() < as.Rhs.Len() {
-                       as.Lhs.Append(argvar(param.Type, as.Lhs.Len()))
+               x := len(as.Lhs)
+               for len(as.Lhs) < len(as.Rhs) {
+                       as.Lhs.Append(argvar(param.Type, len(as.Lhs)))
                }
-               varargs := as.Lhs.Slice()[x:]
+               varargs := as.Lhs[x:]
 
                vas = ir.NewAssignStmt(base.Pos, nil, nil)
                vas.X = inlParam(param, vas, inlvars)
                }
        }
 
-       if as.Rhs.Len() != 0 {
+       if len(as.Rhs) != 0 {
                ninit.Append(typecheck(as, ctxStmt))
        }
 
        }
        subst.edit = subst.node
 
-       body := subst.list(ir.AsNodes(fn.Inl.Body))
+       body := subst.list(ir.Nodes(fn.Inl.Body))
 
        lab := ir.NewLabelStmt(base.Pos, retlabel)
        body = append(body, lab)
        //dumplist("ninit post", ninit);
 
        call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
-       call.PtrInit().Set(ninit.Slice())
+       call.PtrInit().Set(ninit)
        call.Body.Set(body)
        call.ReturnVars.Set(retvars)
        call.SetType(n.Type())
 
 // list inlines a list of nodes.
 func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
-       s := make([]ir.Node, 0, ll.Len())
-       for _, n := range ll.Slice() {
+       s := make([]ir.Node, 0, len(ll))
+       for _, n := range ll {
                s = append(s, subst.node(n))
        }
        return s
                // this return is guaranteed to belong to the current inlined function.
                n := n.(*ir.ReturnStmt)
                init := subst.list(n.Init())
-               if len(subst.retvars) != 0 && n.Results.Len() != 0 {
+               if len(subst.retvars) != 0 && len(n.Results) != 0 {
                        as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
 
                        // Make a shallow copy of retvars.
                        as.Rhs.Set(subst.list(n.Results))
 
                        if subst.delayretvars {
-                               for _, n := range as.Lhs.Slice() {
+                               for _, n := range as.Lhs {
                                        as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
                                        n.Name().Defn = as
                                }
 
        for i, stmt := range stmts {
                s := p.stmtFall(stmt, fallOK && i+1 == len(stmts))
                if s == nil {
-               } else if s.Op() == ir.OBLOCK && s.(*ir.BlockStmt).List.Len() > 0 {
+               } else if s.Op() == ir.OBLOCK && len(s.(*ir.BlockStmt).List) > 0 {
                        // Inline non-empty block.
                        // Empty blocks must be preserved for checkreturn.
-                       nodes = append(nodes, s.(*ir.BlockStmt).List.Slice()...)
+                       nodes = append(nodes, s.(*ir.BlockStmt).List...)
                } else {
                        nodes = append(nodes, s)
                }
                }
                n := ir.NewReturnStmt(p.pos(stmt), nil)
                n.Results.Set(results)
-               if n.Results.Len() == 0 && Curfn != nil {
+               if len(n.Results) == 0 && Curfn != nil {
                        for _, ln := range Curfn.Dcl {
                                if ln.Class_ == ir.PPARAM {
                                        continue
        p.openScope(stmt.Pos())
        n := ir.NewIfStmt(p.pos(stmt), nil, nil, nil)
        if stmt.Init != nil {
-               n.PtrInit().Set1(p.stmt(stmt.Init))
+               *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)}
        }
        if stmt.Cond != nil {
                n.Cond = p.expr(stmt.Cond)
                e := p.stmt(stmt.Else)
                if e.Op() == ir.OBLOCK {
                        e := e.(*ir.BlockStmt)
-                       n.Else.Set(e.List.Slice())
+                       n.Else.Set(e.List)
                } else {
-                       n.Else.Set1(e)
+                       n.Else = []ir.Node{e}
                }
        }
        p.closeAnotherScope()
 
        n := ir.NewForStmt(p.pos(stmt), nil, nil, nil, nil)
        if stmt.Init != nil {
-               n.PtrInit().Set1(p.stmt(stmt.Init))
+               *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)}
        }
        if stmt.Cond != nil {
                n.Cond = p.expr(stmt.Cond)
        p.openScope(stmt.Pos())
        n := ir.NewSwitchStmt(p.pos(stmt), nil, nil)
        if stmt.Init != nil {
-               n.PtrInit().Set1(p.stmt(stmt.Init))
+               *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)}
        }
        if stmt.Tag != nil {
                n.Tag = p.expr(stmt.Tag)
                if tswitch != nil && tswitch.Tag != nil {
                        nn := NewName(tswitch.Tag.Sym())
                        declare(nn, dclcontext)
-                       n.Vars.Set1(nn)
+                       n.Vars = []ir.Node{nn}
                        // keep track of the instances for reporting unused
                        nn.Defn = tswitch
                }
                }
 
                n.Body.Set(p.stmtsFall(body, true))
-               if l := n.Body.Len(); l > 0 && n.Body.Index(l-1).Op() == ir.OFALL {
+               if l := len(n.Body); l > 0 && n.Body[l-1].Op() == ir.OFALL {
                        if tswitch != nil {
                                base.Errorf("cannot fallthrough in type switch")
                        }
 
                n := ir.NewCaseStmt(p.pos(clause), nil, nil)
                if clause.Comm != nil {
-                       n.List.Set1(p.stmt(clause.Comm))
+                       n.List = []ir.Node{p.stmt(clause.Comm)}
                }
                n.Body.Set(p.stmts(clause.Body))
                nodes = append(nodes, n)
        if ls != nil {
                if ls.Op() == ir.OBLOCK {
                        ls := ls.(*ir.BlockStmt)
-                       l = append(l, ls.List.Slice()...)
+                       l = append(l, ls.List...)
                } else {
                        l = append(l, ls)
                }
 
                replaced = true
        case ir.OSTRUCTLIT:
                n := n.(*ir.CompLitExpr)
-               for _, elem := range n.List.Slice() {
+               for _, elem := range n.List {
                        elem := elem.(*ir.StructKeyExpr)
                        if mapKeyReplaceStrConv(elem.Value) {
                                replaced = true
                }
        case ir.OARRAYLIT:
                n := n.(*ir.CompLitExpr)
-               for _, elem := range n.List.Slice() {
+               for _, elem := range n.List {
                        if elem.Op() == ir.OKEY {
                                elem = elem.(*ir.KeyExpr).Value
                        }
 
 // stmtList orders each of the statements in the list.
 func (o *Order) stmtList(l ir.Nodes) {
-       s := l.Slice()
+       s := l
        for i := range s {
                orderMakeSliceCopy(s[i:])
                o.stmt(s[i])
        if ir.MayBeShared(n) {
                // For concurrency safety, don't mutate potentially shared nodes.
                // First, ensure that no work is required here.
-               if n.Init().Len() > 0 {
+               if len(n.Init()) > 0 {
                        base.Fatalf("order.init shared node with ninit")
                }
                return
 // call orders the call expression n.
 // n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
 func (o *Order) call(nn ir.Node) {
-       if nn.Init().Len() > 0 {
+       if len(nn.Init()) > 0 {
                // Caller should have already called o.init(nn).
                base.Fatalf("%v with unexpected ninit", nn.Op())
        }
        // Check for "unsafe-uintptr" tag provided by escape analysis.
        for i, param := range n.X.Type().Params().FieldSlice() {
                if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag {
-                       if arg := n.Args.Index(i); arg.Op() == ir.OSLICELIT {
+                       if arg := n.Args[i]; arg.Op() == ir.OSLICELIT {
                                arg := arg.(*ir.CompLitExpr)
-                               for _, elt := range arg.List.Slice() {
+                               for _, elt := range arg.List {
                                        keepAlive(elt)
                                }
                        } else {
        case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
                n := n.(*ir.AssignListStmt)
                var post []ir.Node
-               for i, m := range n.Lhs.Slice() {
+               for i, m := range n.Lhs {
                        switch {
                        case m.Op() == ir.OINDEXMAP:
                                m := m.(*ir.IndexExpr)
                                fallthrough
                        case instrumenting && n.Op() == ir.OAS2FUNC && !ir.IsBlank(m):
                                t := o.newTemp(m.Type(), false)
-                               n.Lhs.SetIndex(i, t)
+                               n.Lhs[i] = t
                                a := ir.NewAssignStmt(base.Pos, m, t)
                                post = append(post, typecheck(a, ctxStmt))
                        }
        // We need to make sure the RHS won't panic.  See issue 22881.
        if r.Op() == ir.OAPPEND {
                r := r.(*ir.CallExpr)
-               s := r.Args.Slice()[1:]
+               s := r.Args[1:]
                for i, n := range s {
                        s[i] = o.cheapExpr(n)
                }
                n := n.(*ir.AssignListStmt)
                t := o.markTemp()
                o.exprList(n.Lhs)
-               o.init(n.Rhs.First())
-               o.call(n.Rhs.First())
+               o.init(n.Rhs[0])
+               o.call(n.Rhs[0])
                o.as2(n)
                o.cleanTemp(t)
 
                t := o.markTemp()
                o.exprList(n.Lhs)
 
-               switch r := n.Rhs.First(); r.Op() {
+               switch r := n.Rhs[0]; r.Op() {
                case ir.ODOTTYPE2:
                        r := r.(*ir.TypeAssertExpr)
                        r.X = o.expr(r.X, nil)
        case ir.ODELETE:
                n := n.(*ir.CallExpr)
                t := o.markTemp()
-               n.Args.SetFirst(o.expr(n.Args.First(), nil))
-               n.Args.SetSecond(o.expr(n.Args.Second(), nil))
-               n.Args.SetSecond(o.mapKeyTemp(n.Args.First().Type(), n.Args.Second()))
+               n.Args[0] = o.expr(n.Args[0], nil)
+               n.Args[1] = o.expr(n.Args[1], nil)
+               n.Args[1] = o.mapKeyTemp(n.Args[0].Type(), n.Args[1])
                o.out = append(o.out, n)
                o.cleanTemp(t)
 
                        base.Fatalf("order.stmt range %v", n.Type())
 
                case types.TARRAY, types.TSLICE:
-                       if n.Vars.Len() < 2 || ir.IsBlank(n.Vars.Second()) {
+                       if len(n.Vars) < 2 || ir.IsBlank(n.Vars[1]) {
                                // for i := range x will only use x once, to compute len(x).
                                // No need to copy it.
                                break
        case ir.OSELECT:
                n := n.(*ir.SelectStmt)
                t := o.markTemp()
-               for _, ncas := range n.Cases.Slice() {
+               for _, ncas := range n.Cases {
                        ncas := ncas.(*ir.CaseStmt)
                        r := ncas.Comm
                        setlineno(ncas)
 
                        // Append any new body prologue to ninit.
                        // The next loop will insert ninit into nbody.
-                       if ncas.Init().Len() != 0 {
+                       if len(ncas.Init()) != 0 {
                                base.Fatalf("order select ninit")
                        }
                        if r == nil {
                        case ir.OSELRECV2:
                                // case x, ok = <-c
                                r := r.(*ir.AssignListStmt)
-                               recv := r.Rhs.First().(*ir.UnaryExpr)
+                               recv := r.Rhs[0].(*ir.UnaryExpr)
                                recv.X = o.expr(recv.X, nil)
                                if !ir.IsAutoTmp(recv.X) {
                                        recv.X = o.copyExpr(recv.X)
                                }
-                               init := r.PtrInit().Slice()
+                               init := *r.PtrInit()
                                r.PtrInit().Set(nil)
 
                                colas := r.Def
                                do := func(i int, t *types.Type) {
-                                       n := r.Lhs.Index(i)
+                                       n := r.Lhs[i]
                                        if ir.IsBlank(n) {
                                                return
                                        }
                                        tmp := o.newTemp(t, t.HasPointers())
                                        as := typecheck(ir.NewAssignStmt(base.Pos, n, conv(tmp, n.Type())), ctxStmt)
                                        ncas.PtrInit().Append(as)
-                                       (&r.Lhs).SetIndex(i, tmp)
+                                       r.Lhs[i] = tmp
                                }
                                do(0, recv.X.Type().Elem())
                                do(1, types.Types[types.TBOOL])
 
                        case ir.OSEND:
                                r := r.(*ir.SendStmt)
-                               if r.Init().Len() != 0 {
+                               if len(r.Init()) != 0 {
                                        ir.DumpList("ninit", r.Init())
                                        base.Fatalf("ninit on select send")
                                }
                // Now that we have accumulated all the temporaries, clean them.
                // Also insert any ninit queued during the previous loop.
                // (The temporary cleaning must follow that ninit work.)
-               for _, cas := range n.Cases.Slice() {
+               for _, cas := range n.Cases {
                        cas := cas.(*ir.CaseStmt)
                        orderBlock(&cas.Body, o.free)
                        cas.Body.Prepend(o.cleanTempNoPop(t)...)
 
                        // TODO(mdempsky): Is this actually necessary?
                        // walkselect appears to walk Ninit.
-                       cas.Body.Prepend(cas.Init().Slice()...)
+                       cas.Body.Prepend(cas.Init()...)
                        cas.PtrInit().Set(nil)
                }
 
 
                t := o.markTemp()
                n.Tag = o.expr(n.Tag, nil)
-               for _, ncas := range n.Cases.Slice() {
+               for _, ncas := range n.Cases {
                        ncas := ncas.(*ir.CaseStmt)
                        o.exprListInPlace(ncas.List)
                        orderBlock(&ncas.Body, o.free)
 }
 
 func hasDefaultCase(n *ir.SwitchStmt) bool {
-       for _, ncas := range n.Cases.Slice() {
+       for _, ncas := range n.Cases {
                ncas := ncas.(*ir.CaseStmt)
-               if ncas.List.Len() == 0 {
+               if len(ncas.List) == 0 {
                        return true
                }
        }
 
 // exprList orders the expression list l into o.
 func (o *Order) exprList(l ir.Nodes) {
-       s := l.Slice()
+       s := l
        for i := range s {
                s[i] = o.expr(s[i], nil)
        }
 // exprListInPlace orders the expression list l but saves
 // the side effects on the individual expression ninit lists.
 func (o *Order) exprListInPlace(l ir.Nodes) {
-       s := l.Slice()
+       s := l
        for i := range s {
                s[i] = o.exprInPlace(s[i])
        }
                n := n.(*ir.AddStringExpr)
                o.exprList(n.List)
 
-               if n.List.Len() > 5 {
-                       t := types.NewArray(types.Types[types.TSTRING], int64(n.List.Len()))
+               if len(n.List) > 5 {
+                       t := types.NewArray(types.Types[types.TSTRING], int64(len(n.List)))
                        n.Prealloc = o.newTemp(t, false)
                }
 
                hasbyte := false
 
                haslit := false
-               for _, n1 := range n.List.Slice() {
+               for _, n1 := range n.List {
                        hasbyte = hasbyte || n1.Op() == ir.OBYTES2STR
                        haslit = haslit || n1.Op() == ir.OLITERAL && len(ir.StringVal(n1)) != 0
                }
 
                if haslit && hasbyte {
-                       for _, n2 := range n.List.Slice() {
+                       for _, n2 := range n.List {
                                if n2.Op() == ir.OBYTES2STR {
                                        n2 := n2.(*ir.ConvExpr)
                                        n2.SetOp(ir.OBYTES2STRTMP)
                // Check for append(x, make([]T, y)...) .
                n := n.(*ir.CallExpr)
                if isAppendOfMake(n) {
-                       n.Args.SetFirst(o.expr(n.Args.First(), nil)) // order x
-                       mk := n.Args.Second().(*ir.MakeExpr)
+                       n.Args[0] = o.expr(n.Args[0], nil) // order x
+                       mk := n.Args[1].(*ir.MakeExpr)
                        mk.Len = o.expr(mk.Len, nil) // order y
                } else {
                        o.exprList(n.Args)
                }
 
-               if lhs == nil || lhs.Op() != ir.ONAME && !samesafeexpr(lhs, n.Args.First()) {
+               if lhs == nil || lhs.Op() != ir.ONAME && !samesafeexpr(lhs, n.Args[0]) {
                        return o.copyExpr(n)
                }
                return n
                // the keys and values before storing any of them to the map.
                // See issue 26552.
                n := n.(*ir.CompLitExpr)
-               entries := n.List.Slice()
+               entries := n.List
                statics := entries[:0]
                var dynamics []*ir.KeyExpr
                for _, r := range entries {
 func (o *Order) as2(n *ir.AssignListStmt) {
        tmplist := []ir.Node{}
        left := []ir.Node{}
-       for ni, l := range n.Lhs.Slice() {
+       for ni, l := range n.Lhs {
                if !ir.IsBlank(l) {
                        tmp := o.newTemp(l.Type(), l.Type().HasPointers())
-                       n.Lhs.SetIndex(ni, tmp)
+                       n.Lhs[ni] = tmp
                        tmplist = append(tmplist, tmp)
                        left = append(left, l)
                }
 // Just like as2, this also adds temporaries to ensure left-to-right assignment.
 func (o *Order) okAs2(n *ir.AssignListStmt) {
        var tmp1, tmp2 ir.Node
-       if !ir.IsBlank(n.Lhs.First()) {
-               typ := n.Rhs.First().Type()
+       if !ir.IsBlank(n.Lhs[0]) {
+               typ := n.Rhs[0].Type()
                tmp1 = o.newTemp(typ, typ.HasPointers())
        }
 
-       if !ir.IsBlank(n.Lhs.Second()) {
+       if !ir.IsBlank(n.Lhs[1]) {
                tmp2 = o.newTemp(types.Types[types.TBOOL], false)
        }
 
        o.out = append(o.out, n)
 
        if tmp1 != nil {
-               r := ir.NewAssignStmt(base.Pos, n.Lhs.First(), tmp1)
+               r := ir.NewAssignStmt(base.Pos, n.Lhs[0], tmp1)
                o.mapAssign(typecheck(r, ctxStmt))
-               n.Lhs.SetFirst(tmp1)
+               n.Lhs[0] = tmp1
        }
        if tmp2 != nil {
-               r := ir.NewAssignStmt(base.Pos, n.Lhs.Second(), conv(tmp2, n.Lhs.Second().Type()))
+               r := ir.NewAssignStmt(base.Pos, n.Lhs[1], conv(tmp2, n.Lhs[1].Type()))
                o.mapAssign(typecheck(r, ctxStmt))
-               n.Lhs.SetSecond(tmp2)
+               n.Lhs[1] = tmp2
        }
 }
 
        // assign parameter offsets
        dowidth(fn.Type())
 
-       if fn.Body.Len() == 0 {
+       if len(fn.Body) == 0 {
                // Initialize ABI wrappers if necessary.
                initLSym(fn, false)
                emitptrargsmap(fn)
                        // since they're most likely to be the slowest.
                        // This helps avoid stragglers.
                        sort.Slice(compilequeue, func(i, j int) bool {
-                               return compilequeue[i].Body.Len() > compilequeue[j].Body.Len()
+                               return len(compilequeue[i].Body) > len(compilequeue[j].Body)
                        })
                }
                var wg sync.WaitGroup
 
 
        // second half of dance, the first half being typecheckrangeExpr
        n.SetTypecheck(1)
-       ls := n.Vars.Slice()
+       ls := n.Vars
        for i1, n1 := range ls {
                if n1.Typecheck() == 0 {
                        ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
        }
 
        decldepth++
-       typecheckslice(n.Body.Slice(), ctxStmt)
+       typecheckslice(n.Body, ctxStmt)
        decldepth--
 }
 
                return
        }
        // delicate little dance.  see typecheckas2
-       ls := n.Vars.Slice()
+       ls := n.Vars
        for i1, n1 := range ls {
                if !ir.DeclaredBy(n1, n) {
                        ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
 
                t1 = t.Elem()
                t2 = nil
-               if n.Vars.Len() == 2 {
+               if len(n.Vars) == 2 {
                        toomany = true
                }
 
                t2 = types.RuneType
        }
 
-       if n.Vars.Len() > 2 || toomany {
+       if len(n.Vars) > 2 || toomany {
                base.ErrorfAt(n.Pos(), "too many variables in range")
        }
 
        var v1, v2 ir.Node
-       if n.Vars.Len() != 0 {
-               v1 = n.Vars.First()
+       if len(n.Vars) != 0 {
+               v1 = n.Vars[0]
        }
-       if n.Vars.Len() > 1 {
-               v2 = n.Vars.Second()
+       if len(n.Vars) > 1 {
+               v2 = n.Vars[1]
        }
 
        // this is not only an optimization but also a requirement in the spec.
        // present."
        if ir.IsBlank(v2) {
                if v1 != nil {
-                       n.Vars.Set1(v1)
+                       n.Vars = []ir.Node{v1}
                }
                v2 = nil
        }
        lno := setlineno(a)
 
        var v1, v2 ir.Node
-       l := nrange.Vars.Len()
+       l := len(nrange.Vars)
        if l > 0 {
-               v1 = nrange.Vars.First()
+               v1 = nrange.Vars[0]
        }
 
        if l > 1 {
-               v2 = nrange.Vars.Second()
+               v2 = nrange.Vars[1]
        }
 
        if ir.IsBlank(v2) {
                        // Use OAS2 to correctly handle assignments
                        // of the form "v1, a[v1] := range".
                        a := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-                       a.Lhs.Set2(v1, v2)
-                       a.Rhs.Set2(hv1, tmp)
+                       a.Lhs = []ir.Node{v1, v2}
+                       a.Rhs = []ir.Node{hv1, tmp}
                        body = []ir.Node{a}
                        break
                }
                // Use OAS2 to correctly handle assignments
                // of the form "v1, a[v1] := range".
                a := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-               a.Lhs.Set2(v1, v2)
-               a.Rhs.Set2(hv1, ir.NewStarExpr(base.Pos, hp))
+               a.Lhs = []ir.Node{v1, v2}
+               a.Rhs = []ir.Node{hv1, ir.NewStarExpr(base.Pos, hp)}
                body = append(body, a)
 
                // Advance pointer as part of the late increment.
                // advancing the pointer is safe and won't go past the
                // end of the allocation.
                as := ir.NewAssignStmt(base.Pos, hp, addptr(hp, t.Elem().Width))
-               nfor.Late.Set1(typecheck(as, ctxStmt))
+               nfor.Late = []ir.Node{typecheck(as, ctxStmt)}
 
        case types.TMAP:
                // order.stmt allocated the iterator for us.
                } else {
                        elem := ir.NewStarExpr(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, elemsym))
                        a := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-                       a.Lhs.Set2(v1, v2)
-                       a.Rhs.Set2(key, elem)
+                       a.Lhs = []ir.Node{v1, v2}
+                       a.Rhs = []ir.Node{key, elem}
                        body = []ir.Node{a}
                }
 
                nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, hb, nodbool(false))
                a := ir.NewAssignListStmt(base.Pos, ir.OAS2RECV, nil, nil)
                a.SetTypecheck(1)
-               a.Lhs.Set2(hv1, hb)
-               a.Rhs.Set1(ir.NewUnaryExpr(base.Pos, ir.ORECV, ha))
-               nfor.Cond.PtrInit().Set1(a)
+               a.Lhs = []ir.Node{hv1, hb}
+               a.Rhs = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.ORECV, ha)}
+               *nfor.Cond.PtrInit() = []ir.Node{a}
                if v1 == nil {
                        body = nil
                } else {
                nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv2, nodintconst(utf8.RuneSelf))
 
                // hv1++
-               nif.Body.Set1(ir.NewAssignStmt(base.Pos, hv1, ir.NewBinaryExpr(base.Pos, ir.OADD, hv1, nodintconst(1))))
+               nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, hv1, ir.NewBinaryExpr(base.Pos, ir.OADD, hv1, nodintconst(1)))}
 
                // } else {
                eif := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-               nif.Else.Set1(eif)
+               nif.Else = []ir.Node{eif}
 
                // hv2, hv1 = decoderune(ha, hv1)
-               eif.Lhs.Set2(hv2, hv1)
+               eif.Lhs = []ir.Node{hv2, hv1}
                fn := syslook("decoderune")
-               eif.Rhs.Set1(mkcall1(fn, fn.Type().Results(), nil, ha, hv1))
+               eif.Rhs = []ir.Node{mkcall1(fn, fn.Type().Results(), nil, ha, hv1)}
 
                body = append(body, nif)
 
                        if v2 != nil {
                                // v1, v2 = hv1t, hv2
                                a := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-                               a.Lhs.Set2(v1, v2)
-                               a.Rhs.Set2(hv1t, hv2)
+                               a.Lhs = []ir.Node{v1, v2}
+                               a.Rhs = []ir.Node{hv1t, hv2}
                                body = append(body, a)
                        } else {
                                // v1 = hv1t
                nfor.PtrInit().Append(init...)
        }
 
-       typecheckslice(nfor.Cond.Init().Slice(), ctxStmt)
+       typecheckslice(nfor.Cond.Init(), ctxStmt)
 
        nfor.Cond = typecheck(nfor.Cond, ctxExpr)
        nfor.Cond = defaultlit(nfor.Cond, nil)
        nfor.Post = typecheck(nfor.Post, ctxStmt)
        typecheckslice(body, ctxStmt)
        nfor.Body.Append(body...)
-       nfor.Body.Append(nrange.Body.Slice()...)
+       nfor.Body.Append(nrange.Body...)
 
        var n ir.Node = nfor
        if ifGuard != nil {
-               ifGuard.Body.Set1(n)
+               ifGuard.Body = []ir.Node{n}
                n = ifGuard
        }
 
                return false
        }
 
-       if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || n.Vars.Len() != 1 {
+       if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || len(n.Vars) != 1 {
                return false
        }
 
-       k := n.Vars.First()
+       k := n.Vars[0]
        if k == nil || ir.IsBlank(k) {
                return false
        }
                return false
        }
 
-       if n.Body.Len() != 1 {
+       if len(n.Body) != 1 {
                return false
        }
 
-       stmt := n.Body.First() // only stmt in body
+       stmt := n.Body[0] // only stmt in body
        if stmt == nil || stmt.Op() != ir.ODELETE {
                return false
        }
 
        m := n.X
-       if delete := stmt.(*ir.CallExpr); !samesafeexpr(delete.Args.First(), m) || !samesafeexpr(delete.Args.Second(), k) {
+       if delete := stmt.(*ir.CallExpr); !samesafeexpr(delete.Args[0], m) || !samesafeexpr(delete.Args[1], k) {
                return false
        }
 
                return nil
        }
 
-       if loop.Body.Len() != 1 || loop.Body.First() == nil {
+       if len(loop.Body) != 1 || loop.Body[0] == nil {
                return nil
        }
 
-       stmt1 := loop.Body.First() // only stmt in body
+       stmt1 := loop.Body[0] // only stmt in body
        if stmt1.Op() != ir.OAS {
                return nil
        }
 
        n.Cond = typecheck(n.Cond, ctxExpr)
        n.Cond = defaultlit(n.Cond, nil)
-       typecheckslice(n.Body.Slice(), ctxStmt)
+       typecheckslice(n.Body, ctxStmt)
        return walkstmt(n)
 }
 
 
 func typecheckselect(sel *ir.SelectStmt) {
        var def ir.Node
        lno := setlineno(sel)
-       typecheckslice(sel.Init().Slice(), ctxStmt)
-       for _, ncase := range sel.Cases.Slice() {
+       typecheckslice(sel.Init(), ctxStmt)
+       for _, ncase := range sel.Cases {
                ncase := ncase.(*ir.CaseStmt)
 
-               if ncase.List.Len() == 0 {
+               if len(ncase.List) == 0 {
                        // default
                        if def != nil {
                                base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
                        } else {
                                def = ncase
                        }
-               } else if ncase.List.Len() > 1 {
+               } else if len(ncase.List) > 1 {
                        base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
                } else {
-                       ncase.List.SetFirst(typecheck(ncase.List.First(), ctxStmt))
-                       n := ncase.List.First()
+                       ncase.List[0] = typecheck(ncase.List[0], ctxStmt)
+                       n := ncase.List[0]
                        ncase.Comm = n
                        ncase.List.Set(nil)
                        oselrecv2 := func(dst, recv ir.Node, colas bool) {
                                n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil)
-                               n.Lhs.Set2(dst, ir.BlankNode)
-                               n.Rhs.Set1(recv)
+                               n.Lhs = []ir.Node{dst, ir.BlankNode}
+                               n.Rhs = []ir.Node{recv}
                                n.Def = colas
                                n.SetTypecheck(1)
                                ncase.Comm = n
 
                        case ir.OAS2RECV:
                                n := n.(*ir.AssignListStmt)
-                               if n.Rhs.First().Op() != ir.ORECV {
+                               if n.Rhs[0].Op() != ir.ORECV {
                                        base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
                                        break
                                }
                        }
                }
 
-               typecheckslice(ncase.Body.Slice(), ctxStmt)
+               typecheckslice(ncase.Body, ctxStmt)
        }
 
        base.Pos = lno
 
 func walkselect(sel *ir.SelectStmt) {
        lno := setlineno(sel)
-       if sel.Compiled.Len() != 0 {
+       if len(sel.Compiled) != 0 {
                base.Fatalf("double walkselect")
        }
 
-       init := sel.Init().Slice()
+       init := sel.Init()
        sel.PtrInit().Set(nil)
 
        init = append(init, walkselectcases(sel.Cases)...)
        sel.Cases = ir.Nodes{}
 
        sel.Compiled.Set(init)
-       walkstmtlist(sel.Compiled.Slice())
+       walkstmtlist(sel.Compiled)
 
        base.Pos = lno
 }
 
 func walkselectcases(cases ir.Nodes) []ir.Node {
-       ncas := cases.Len()
+       ncas := len(cases)
        sellineno := base.Pos
 
        // optimization: zero-case select
 
        // optimization: one-case select: single op.
        if ncas == 1 {
-               cas := cases.First().(*ir.CaseStmt)
+               cas := cases[0].(*ir.CaseStmt)
                setlineno(cas)
-               l := cas.Init().Slice()
+               l := cas.Init()
                if cas.Comm != nil { // not default:
                        n := cas.Comm
-                       l = append(l, n.Init().Slice()...)
+                       l = append(l, n.Init()...)
                        n.PtrInit().Set(nil)
                        switch n.Op() {
                        default:
 
                        case ir.OSELRECV2:
                                r := n.(*ir.AssignListStmt)
-                               if ir.IsBlank(r.Lhs.First()) && ir.IsBlank(r.Lhs.Second()) {
-                                       n = r.Rhs.First()
+                               if ir.IsBlank(r.Lhs[0]) && ir.IsBlank(r.Lhs[1]) {
+                                       n = r.Rhs[0]
                                        break
                                }
                                r.SetOp(ir.OAS2RECV)
                        l = append(l, n)
                }
 
-               l = append(l, cas.Body.Slice()...)
+               l = append(l, cas.Body...)
                l = append(l, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil))
                return l
        }
        // convert case value arguments to addresses.
        // this rewrite is used by both the general code and the next optimization.
        var dflt *ir.CaseStmt
-       for _, cas := range cases.Slice() {
+       for _, cas := range cases {
                cas := cas.(*ir.CaseStmt)
                setlineno(cas)
                n := cas.Comm
 
                case ir.OSELRECV2:
                        n := n.(*ir.AssignListStmt)
-                       if !ir.IsBlank(n.Lhs.First()) {
-                               n.Lhs.SetIndex(0, nodAddr(n.Lhs.First()))
-                               n.Lhs.SetIndex(0, typecheck(n.Lhs.First(), ctxExpr))
+                       if !ir.IsBlank(n.Lhs[0]) {
+                               n.Lhs[0] = nodAddr(n.Lhs[0])
+                               n.Lhs[0] = typecheck(n.Lhs[0], ctxExpr)
                        }
                }
        }
 
        // optimization: two-case select but one is default: single non-blocking op.
        if ncas == 2 && dflt != nil {
-               cas := cases.First().(*ir.CaseStmt)
+               cas := cases[0].(*ir.CaseStmt)
                if cas == dflt {
-                       cas = cases.Second().(*ir.CaseStmt)
+                       cas = cases[1].(*ir.CaseStmt)
                }
 
                n := cas.Comm
                setlineno(n)
                r := ir.NewIfStmt(base.Pos, nil, nil, nil)
-               r.PtrInit().Set(cas.Init().Slice())
+               r.PtrInit().Set(cas.Init())
                var call ir.Node
                switch n.Op() {
                default:
 
                case ir.OSELRECV2:
                        n := n.(*ir.AssignListStmt)
-                       recv := n.Rhs.First().(*ir.UnaryExpr)
+                       recv := n.Rhs[0].(*ir.UnaryExpr)
                        ch := recv.X
-                       elem := n.Lhs.First()
+                       elem := n.Lhs[0]
                        if ir.IsBlank(elem) {
                                elem = nodnil()
                        }
-                       if ir.IsBlank(n.Lhs.Second()) {
+                       if ir.IsBlank(n.Lhs[1]) {
                                // if selectnbrecv(&v, c) { body } else { default body }
                                call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch)
                        } else {
                                // TODO(cuonglm): make this use selectnbrecv()
                                // if selectnbrecv2(&v, &received, c) { body } else { default body }
-                               receivedp := typecheck(nodAddr(n.Lhs.Second()), ctxExpr)
+                               receivedp := typecheck(nodAddr(n.Lhs[1]), ctxExpr)
                                call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
                        }
                }
 
                r.Cond = typecheck(call, ctxExpr)
-               r.Body.Set(cas.Body.Slice())
-               r.Else.Set(append(dflt.Init().Slice(), dflt.Body.Slice()...))
+               r.Body.Set(cas.Body)
+               r.Else.Set(append(dflt.Init(), dflt.Body...))
                return []ir.Node{r, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)}
        }
 
        }
 
        // register cases
-       for _, cas := range cases.Slice() {
+       for _, cas := range cases {
                cas := cas.(*ir.CaseStmt)
                setlineno(cas)
 
-               init = append(init, cas.Init().Slice()...)
+               init = append(init, cas.Init()...)
                cas.PtrInit().Set(nil)
 
                n := cas.Comm
                        n := n.(*ir.AssignListStmt)
                        nrecvs++
                        i = ncas - nrecvs
-                       recv := n.Rhs.First().(*ir.UnaryExpr)
+                       recv := n.Rhs[0].(*ir.UnaryExpr)
                        c = recv.X
-                       elem = n.Lhs.First()
+                       elem = n.Lhs[0]
                }
 
                casorder[i] = cas
        chosen := temp(types.Types[types.TINT])
        recvOK := temp(types.Types[types.TBOOL])
        r := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-       r.Lhs.Set2(chosen, recvOK)
+       r.Lhs = []ir.Node{chosen, recvOK}
        fn := syslook("selectgo")
-       r.Rhs.Set1(mkcall1(fn, fn.Type().Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil)))
+       r.Rhs = []ir.Node{mkcall1(fn, fn.Type().Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil))}
        init = append(init, typecheck(r, ctxStmt))
 
        // selv and order are no longer alive after selectgo.
 
                if n := cas.Comm; n != nil && n.Op() == ir.OSELRECV2 {
                        n := n.(*ir.AssignListStmt)
-                       if !ir.IsBlank(n.Lhs.Second()) {
-                               x := ir.NewAssignStmt(base.Pos, n.Lhs.Second(), recvOK)
+                       if !ir.IsBlank(n.Lhs[1]) {
+                               x := ir.NewAssignStmt(base.Pos, n.Lhs[1], recvOK)
                                r.Body.Append(typecheck(x, ctxStmt))
                        }
                }
 
-               r.Body.AppendNodes(&cas.Body)
+               r.Body.Append(cas.Body.Take()...)
                r.Body.Append(ir.NewBranchStmt(base.Pos, ir.OBREAK, nil))
                init = append(init, r)
        }
 
                if !top {
                        return initDynamic
                }
-               if n.Len/4 > int64(n.List.Len()) {
+               if n.Len/4 > int64(len(n.List)) {
                        // <25% of entries have explicit values.
                        // Very rough estimation, it takes 4 bytes of instructions
                        // to initialize 1 byte of result. So don't use a static
        lit := n.(*ir.CompLitExpr)
 
        var mode initGenType
-       for _, n1 := range lit.List.Slice() {
+       for _, n1 := range lit.List {
                switch n1.Op() {
                case ir.OKEY:
                        n1 = n1.(*ir.KeyExpr).Value
                return false
        case ir.OARRAYLIT:
                n := n.(*ir.CompLitExpr)
-               for _, r := range n.List.Slice() {
+               for _, r := range n.List {
                        if r.Op() == ir.OKEY {
                                r = r.(*ir.KeyExpr).Value
                        }
                return true
        case ir.OSTRUCTLIT:
                n := n.(*ir.CompLitExpr)
-               for _, r := range n.List.Slice() {
+               for _, r := range n.List {
                        r := r.(*ir.StructKeyExpr)
                        if !isStaticCompositeLiteral(r.Value) {
                                return false
                base.Fatalf("fixedlit bad op: %v", n.Op())
        }
 
-       for _, r := range n.List.Slice() {
+       for _, r := range n.List {
                a, value := splitnode(r)
                if a == ir.BlankNode && !anySideEffects(value) {
                        // Discard.
 
        // put dynamics into array (5)
        var index int64
-       for _, value := range n.List.Slice() {
+       for _, value := range n.List {
                if value.Op() == ir.OKEY {
                        kv := value.(*ir.KeyExpr)
                        index = indexconst(kv.Key)
        // make the map var
        a := ir.NewCallExpr(base.Pos, ir.OMAKE, nil, nil)
        a.SetEsc(n.Esc())
-       a.Args.Set2(ir.TypeNode(n.Type()), nodintconst(int64(n.List.Len())))
+       a.Args = []ir.Node{ir.TypeNode(n.Type()), nodintconst(int64(len(n.List)))}
        litas(m, a, init)
 
-       entries := n.List.Slice()
+       entries := n.List
 
        // The order pass already removed any dynamic (runtime-computed) entries.
        // All remaining entries are static. Double-check that.
                body := ir.NewAssignStmt(base.Pos, lhs, rhs)
 
                loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil)
-               loop.Body.Set1(body)
-               loop.PtrInit().Set1(zero)
+               loop.Body = []ir.Node{body}
+               *loop.PtrInit() = []ir.Node{zero}
 
                appendWalkStmt(init, loop)
                return
                        base.Fatalf("anylit: not struct/array")
                }
 
-               if isSimpleName(var_) && n.List.Len() > 4 {
+               if isSimpleName(var_) && len(n.List) > 4 {
                        // lay out static data
                        vstat := readonlystaticname(t)
 
                        components = int64(t.NumFields())
                }
                // initialization of an array or struct with unspecified components (missing fields or arrays)
-               if isSimpleName(var_) || int64(n.List.Len()) < components {
+               if isSimpleName(var_) || int64(len(n.List)) < components {
                        appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
                }
 
        case ir.OARRAYLIT, ir.OSLICELIT:
                n := n.(*ir.CompLitExpr)
                var k int64
-               for _, a := range n.List.Slice() {
+               for _, a := range n.List {
                        if a.Op() == ir.OKEY {
                                kv := a.(*ir.KeyExpr)
                                k = indexconst(kv.Key)
 
        case ir.OSTRUCTLIT:
                n := n.(*ir.CompLitExpr)
-               for _, a := range n.List.Slice() {
+               for _, a := range n.List {
                        if a.Op() != ir.OSTRUCTKEY {
                                base.Fatalf("initplan structlit")
                        }
 
        case ir.OMAPLIT:
                n := n.(*ir.CompLitExpr)
-               for _, a := range n.List.Slice() {
+               for _, a := range n.List {
                        if a.Op() != ir.OKEY {
                                base.Fatalf("initplan maplit")
                        }
 
        case ir.OARRAYLIT:
                n := n.(*ir.CompLitExpr)
-               for _, n1 := range n.List.Slice() {
+               for _, n1 := range n.List {
                        if n1.Op() == ir.OKEY {
                                n1 = n1.(*ir.KeyExpr).Value
                        }
 
        case ir.OSTRUCTLIT:
                n := n.(*ir.CompLitExpr)
-               for _, n1 := range n.List.Slice() {
+               for _, n1 := range n.List {
                        n1 := n1.(*ir.StructKeyExpr)
                        if !isZero(n1.Value) {
                                return false
 
                // that we don't track correctly.
                s.hasOpenDefers = false
        }
-       if s.hasOpenDefers && s.curfn.Exit.Len() > 0 {
+       if s.hasOpenDefers && len(s.curfn.Exit) > 0 {
                // Skip doing open defers if there is any extra exit code (likely
                // copying heap-allocated return values or race detection), since
                // we will not generate that code in the case of the extra
 
 // stmtList converts the statement list n to SSA and adds it to s.
 func (s *state) stmtList(l ir.Nodes) {
-       for _, n := range l.Slice() {
+       for _, n := range l {
                s.stmt(n)
        }
 }
 
        case ir.OAS2DOTTYPE:
                n := n.(*ir.AssignListStmt)
-               res, resok := s.dottype(n.Rhs.First().(*ir.TypeAssertExpr), true)
+               res, resok := s.dottype(n.Rhs[0].(*ir.TypeAssertExpr), true)
                deref := false
-               if !canSSAType(n.Rhs.First().Type()) {
+               if !canSSAType(n.Rhs[0].Type()) {
                        if res.Op != ssa.OpLoad {
                                s.Fatalf("dottype of non-load")
                        }
                        deref = true
                        res = res.Args[0]
                }
-               s.assign(n.Lhs.First(), res, deref, 0)
-               s.assign(n.Lhs.Second(), resok, false, 0)
+               s.assign(n.Lhs[0], res, deref, 0)
+               s.assign(n.Lhs[1], resok, false, 0)
                return
 
        case ir.OAS2FUNC:
                // We come here only when it is an intrinsic call returning two values.
                n := n.(*ir.AssignListStmt)
-               call := n.Rhs.First().(*ir.CallExpr)
+               call := n.Rhs[0].(*ir.CallExpr)
                if !IsIntrinsicCall(call) {
                        s.Fatalf("non-intrinsic AS2FUNC not expanded %v", call)
                }
                v := s.intrinsicCall(call)
-               v1 := s.newValue1(ssa.OpSelect0, n.Lhs.First().Type(), v)
-               v2 := s.newValue1(ssa.OpSelect1, n.Lhs.Second().Type(), v)
-               s.assign(n.Lhs.First(), v1, false, 0)
-               s.assign(n.Lhs.Second(), v2, false, 0)
+               v1 := s.newValue1(ssa.OpSelect0, n.Lhs[0].Type(), v)
+               v2 := s.newValue1(ssa.OpSelect1, n.Lhs[1].Type(), v)
+               s.assign(n.Lhs[0], v1, false, 0)
+               s.assign(n.Lhs[1], v2, false, 0)
                return
 
        case ir.ODCL:
                                // Check whether we're writing the result of an append back to the same slice.
                                // If so, we handle it specially to avoid write barriers on the fast
                                // (non-growth) path.
-                               if !samesafeexpr(n.X, rhs.Args.First()) || base.Flag.N != 0 {
+                               if !samesafeexpr(n.X, rhs.Args[0]) || base.Flag.N != 0 {
                                        break
                                }
                                // If the slice can be SSA'd, it'll be on the stack,
                        likely = 1
                }
                var bThen *ssa.Block
-               if n.Body.Len() != 0 {
+               if len(n.Body) != 0 {
                        bThen = s.f.NewBlock(ssa.BlockPlain)
                } else {
                        bThen = bEnd
                }
                var bElse *ssa.Block
-               if n.Else.Len() != 0 {
+               if len(n.Else) != 0 {
                        bElse = s.f.NewBlock(ssa.BlockPlain)
                } else {
                        bElse = bEnd
                }
                s.condBranch(n.Cond, bThen, bElse, likely)
 
-               if n.Body.Len() != 0 {
+               if len(n.Body) != 0 {
                        s.startBlock(bThen)
                        s.stmtList(n.Body)
                        if b := s.endBlock(); b != nil {
                                b.AddEdgeTo(bEnd)
                        }
                }
-               if n.Else.Len() != 0 {
+               if len(n.Else) != 0 {
                        s.startBlock(bElse)
                        s.stmtList(n.Else)
                        if b := s.endBlock(); b != nil {
        case ir.OSLICEHEADER:
                n := n.(*ir.SliceHeaderExpr)
                p := s.expr(n.Ptr)
-               l := s.expr(n.LenCap.First())
-               c := s.expr(n.LenCap.Second())
+               l := s.expr(n.LenCap[0])
+               c := s.expr(n.LenCap[1])
                return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
 
        case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
        pt := types.NewPtr(et)
 
        // Evaluate slice
-       sn := n.Args.First() // the slice node is the first in the list
+       sn := n.Args[0] // the slice node is the first in the list
 
        var slice, addr *ssa.Value
        if inplace {
        assign := s.f.NewBlock(ssa.BlockPlain)
 
        // Decide if we need to grow
-       nargs := int64(n.Args.Len() - 1)
+       nargs := int64(len(n.Args) - 1)
        p := s.newValue1(ssa.OpSlicePtr, pt, slice)
        l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
        c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
                store bool
        }
        args := make([]argRec, 0, nargs)
-       for _, n := range n.Args.Slice()[1:] {
+       for _, n := range n.Args[1:] {
                if canSSAType(n.Type()) {
                        args = append(args, argRec{v: s.expr(n), store: true})
                } else {
 func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value {
        // Construct map of temps; see comments in s.call about the structure of n.
        temps := map[ir.Node]*ssa.Value{}
-       for _, a := range n.Args.Slice() {
+       for _, a := range n.Args {
                if a.Op() != ir.OAS {
                        s.Fatalf("non-assignment as a temp function argument %v", a.Op())
                }
                // Walk ensures these temporaries are dead outside of n.
                temps[l] = s.expr(r)
        }
-       args := make([]*ssa.Value, n.Rargs.Len())
-       for i, n := range n.Rargs.Slice() {
+       args := make([]*ssa.Value, len(n.Rargs))
+       for i, n := range n.Rargs {
                // Store a value to an argument slot.
                if x, ok := temps[n]; ok {
                        // This is a previously computed temporary.
                opendefer.closureNode = opendefer.closure.Aux.(*ir.Name)
                opendefer.rcvrNode = opendefer.rcvr.Aux.(*ir.Name)
        }
-       for _, argn := range n.Rargs.Slice() {
+       for _, argn := range n.Rargs {
                var v *ssa.Value
                if canSSAType(argn.Type()) {
                        v = s.openDeferSave(nil, argn.Type(), s.expr(argn))
                // Then, store all the arguments of the defer call.
                ft := fn.Type()
                off := t.FieldOff(12)
-               args := n.Rargs.Slice()
+               args := n.Rargs
 
                // Set receiver (for interface calls). Always a pointer.
                if rcvr != nil {
 
                // Write args.
                t := n.X.Type()
-               args := n.Rargs.Slice()
+               args := n.Rargs
                if n.Op() == ir.OCALLMETH {
                        f := t.Recv()
                        ACArg, arg := s.putArg(args[0], f.Type, argStart+f.Offset, testLateExpansion)
                targetITab = target
        } else {
                // Looking for pointer to itab for target type and source interface.
-               targetITab = s.expr(n.Itab.First())
+               targetITab = s.expr(n.Itab[0])
        }
 
        var tmp ir.Node     // temporary for use with large types
 
 func backingArrayPtrLen(n ir.Node) (ptr, length ir.Node) {
        var init ir.Nodes
        c := cheapexpr(n, &init)
-       if c != n || init.Len() != 0 {
+       if c != n || len(init) != 0 {
                base.Fatalf("backingArrayPtrLen not cheap: %v", n)
        }
        ptr = ir.NewUnaryExpr(base.Pos, ir.OSPTR, n)
 }
 
 func calcHasCall(n ir.Node) bool {
-       if n.Init().Len() != 0 {
+       if len(n.Init()) != 0 {
                // TODO(mdempsky): This seems overly conservative.
                return true
        }
                return nil
        }
 
-       if n.Init().Len() != 0 {
-               walkstmtlist(n.Init().Slice())
-               init.AppendNodes(n.PtrInit())
+       if len(n.Init()) != 0 {
+               walkstmtlist(n.Init())
+               init.Append(n.PtrInit().Take()...)
        }
 
        switch n.Op() {
                n := ir.NewIfStmt(base.Pos, nil, nil, nil)
                n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, nodnil())
                call := ir.NewCallExpr(base.Pos, ir.OCALL, syslook("panicwrap"), nil)
-               n.Body.Set1(call)
+               n.Body = []ir.Node{call}
                fn.Body.Append(n)
        }
 
                call.IsDDD = tfn.Type().IsVariadic()
                if method.Type.NumResults() > 0 {
                        ret := ir.NewReturnStmt(base.Pos, nil)
-                       ret.Results.Set1(call)
+                       ret.Results = []ir.Node{call}
                        fn.Body.Append(ret)
                } else {
                        fn.Body.Append(call)
 
        typecheckFunc(fn)
        Curfn = fn
-       typecheckslice(fn.Body.Slice(), ctxStmt)
+       typecheckslice(fn.Body, ctxStmt)
 
        // Inline calls within (*T).M wrappers. This is safe because we only
        // generate those wrappers within the same compilation unit as (T).M.
 
 
 // typecheckswitch typechecks a switch statement.
 func typecheckswitch(n *ir.SwitchStmt) {
-       typecheckslice(n.Init().Slice(), ctxStmt)
+       typecheckslice(n.Init(), ctxStmt)
        if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
                typecheckTypeSwitch(n)
        } else {
        // We don't actually declare the type switch's guarded
        // declaration itself. So if there are no cases, we won't
        // notice that it went unused.
-       if v := guard.Tag; v != nil && !ir.IsBlank(v) && n.Cases.Len() == 0 {
+       if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
                base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
        }
 
        var defCase, nilCase ir.Node
        var ts typeSet
-       for _, ncase := range n.Cases.Slice() {
+       for _, ncase := range n.Cases {
                ncase := ncase.(*ir.CaseStmt)
-               ls := ncase.List.Slice()
+               ls := ncase.List
                if len(ls) == 0 { // default:
                        if defCase != nil {
                                base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
                        ts.add(ncase.Pos(), n1.Type())
                }
 
-               if ncase.Vars.Len() != 0 {
+               if len(ncase.Vars) != 0 {
                        // Assign the clause variable's type.
                        vt := t
                        if len(ls) == 1 {
                                }
                        }
 
-                       nvar := ncase.Vars.First()
+                       nvar := ncase.Vars[0]
                        nvar.SetType(vt)
                        if vt != nil {
                                nvar = typecheck(nvar, ctxExpr|ctxAssign)
                                nvar.SetTypecheck(1)
                                nvar.SetWalkdef(1)
                        }
-                       ncase.Vars.SetFirst(nvar)
+                       ncase.Vars[0] = nvar
                }
 
-               typecheckslice(ncase.Body.Slice(), ctxStmt)
+               typecheckslice(ncase.Body, ctxStmt)
        }
 }
 
 
        var defCase ir.Node
        var cs constSet
-       for _, ncase := range n.Cases.Slice() {
+       for _, ncase := range n.Cases {
                ncase := ncase.(*ir.CaseStmt)
-               ls := ncase.List.Slice()
+               ls := ncase.List
                if len(ls) == 0 { // default:
                        if defCase != nil {
                                base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
                        }
                }
 
-               typecheckslice(ncase.Body.Slice(), ctxStmt)
+               typecheckslice(ncase.Body, ctxStmt)
        }
 }
 
 // walkswitch walks a switch statement.
 func walkswitch(sw *ir.SwitchStmt) {
        // Guard against double walk, see #25776.
-       if sw.Cases.Len() == 0 && sw.Compiled.Len() > 0 {
+       if len(sw.Cases) == 0 && len(sw.Compiled) > 0 {
                return // Was fatal, but eliminating every possible source of double-walking is hard
        }
 
 
        var defaultGoto ir.Node
        var body ir.Nodes
-       for _, ncase := range sw.Cases.Slice() {
+       for _, ncase := range sw.Cases {
                ncase := ncase.(*ir.CaseStmt)
                label := autolabel(".s")
                jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
 
                // Process case dispatch.
-               if ncase.List.Len() == 0 {
+               if len(ncase.List) == 0 {
                        if defaultGoto != nil {
                                base.Fatalf("duplicate default case not detected during typechecking")
                        }
                        defaultGoto = jmp
                }
 
-               for _, n1 := range ncase.List.Slice() {
+               for _, n1 := range ncase.List {
                        s.Add(ncase.Pos(), n1, jmp)
                }
 
                // Process body.
                body.Append(ir.NewLabelStmt(ncase.Pos(), label))
-               body.Append(ncase.Body.Slice()...)
-               if fall, pos := endsInFallthrough(ncase.Body.Slice()); !fall {
+               body.Append(ncase.Body...)
+               if fall, pos := endsInFallthrough(ncase.Body); !fall {
                        br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
                        br.SetPos(pos)
                        body.Append(br)
 
        s.Emit(&sw.Compiled)
        sw.Compiled.Append(defaultGoto)
-       sw.Compiled.AppendNodes(&body)
-       walkstmtlist(sw.Compiled.Slice())
+       sw.Compiled.Append(body.Take()...)
+       walkstmtlist(sw.Compiled)
 }
 
 // An exprSwitch walks an expression switch.
 
 func (s *exprSwitch) Emit(out *ir.Nodes) {
        s.flush()
-       out.AppendNodes(&s.done)
+       out.Append(s.done.Take()...)
 }
 
 func (s *exprSwitch) flush() {
                func(i int, nif *ir.IfStmt) {
                        c := &cc[i]
                        nif.Cond = c.test(s.exprname)
-                       nif.Body.Set1(c.jmp)
+                       nif.Body = []ir.Node{c.jmp}
                },
        )
 }
        // Restricting to constants is simple and probably powerful
        // enough.
 
-       for _, ncase := range sw.Cases.Slice() {
+       for _, ncase := range sw.Cases {
                ncase := ncase.(*ir.CaseStmt)
-               for _, v := range ncase.List.Slice() {
+               for _, v := range ncase.List {
                        if v.Op() != ir.OLITERAL {
                                return false
                        }
        br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
        var defaultGoto, nilGoto ir.Node
        var body ir.Nodes
-       for _, ncase := range sw.Cases.Slice() {
+       for _, ncase := range sw.Cases {
                ncase := ncase.(*ir.CaseStmt)
                var caseVar ir.Node
-               if ncase.Vars.Len() != 0 {
-                       caseVar = ncase.Vars.First()
+               if len(ncase.Vars) != 0 {
+                       caseVar = ncase.Vars[0]
                }
 
                // 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() == ir.OTYPE {
-                       singleType = ncase.List.First().Type()
+               if len(ncase.List) == 1 && ncase.List[0].Op() == ir.OTYPE {
+                       singleType = ncase.List[0].Type()
                }
                caseVarInitialized := false
 
                label := autolabel(".s")
                jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
 
-               if ncase.List.Len() == 0 { // default:
+               if len(ncase.List) == 0 { // default:
                        if defaultGoto != nil {
                                base.Fatalf("duplicate default case not detected during typechecking")
                        }
                        defaultGoto = jmp
                }
 
-               for _, n1 := range ncase.List.Slice() {
+               for _, n1 := range ncase.List {
                        if ir.IsNil(n1) { // case nil:
                                if nilGoto != nil {
                                        base.Fatalf("duplicate nil case not detected during typechecking")
                        typecheckslice(l, ctxStmt)
                        body.Append(l...)
                }
-               body.Append(ncase.Body.Slice()...)
+               body.Append(ncase.Body...)
                body.Append(br)
        }
        sw.Cases.Set(nil)
        if nilGoto == nil {
                nilGoto = defaultGoto
        }
-       ifNil.Body.Set1(nilGoto)
+       ifNil.Body = []ir.Node{nilGoto}
 
        s.Emit(&sw.Compiled)
        sw.Compiled.Append(defaultGoto)
-       sw.Compiled.AppendNodes(&body)
+       sw.Compiled.Append(body.Take()...)
 
-       walkstmtlist(sw.Compiled.Slice())
+       walkstmtlist(sw.Compiled)
 }
 
 // A typeSwitch walks a type switch.
 
        // cv, ok = iface.(type)
        as := ir.NewAssignListStmt(pos, ir.OAS2, nil, nil)
-       as.Lhs.Set2(caseVar, s.okname) // cv, ok =
+       as.Lhs = []ir.Node{caseVar, s.okname} // cv, ok =
        dot := ir.NewTypeAssertExpr(pos, s.facename, nil)
        dot.SetType(typ) // iface.(type)
-       as.Rhs.Set1(dot)
+       as.Rhs = []ir.Node{dot}
        appendWalkStmt(&body, as)
 
        // if ok { goto label }
        nif := ir.NewIfStmt(pos, nil, nil, nil)
        nif.Cond = s.okname
-       nif.Body.Set1(jmp)
+       nif.Body = []ir.Node{jmp}
        body.Append(nif)
 
        if !typ.IsInterface() {
        }
 
        s.flush()
-       s.done.AppendNodes(&body)
+       s.done.Append(body.Take()...)
 }
 
 func (s *typeSwitch) Emit(out *ir.Nodes) {
        s.flush()
-       out.AppendNodes(&s.done)
+       out.Append(s.done.Take()...)
 }
 
 func (s *typeSwitch) flush() {
        for _, c := range cc[1:] {
                last := &merged[len(merged)-1]
                if last.hash == c.hash {
-                       last.body.AppendNodes(&c.body)
+                       last.body.Append(c.body.Take()...)
                } else {
                        merged = append(merged, c)
                }
                        // there's only one type.
                        c := cc[i]
                        nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, s.hashname, nodintconst(int64(c.hash)))
-                       nif.Body.AppendNodes(&c.body)
+                       nif.Body.Append(c.body.Take()...)
                },
        )
 }
 
                        }
                        if r.Op() == ir.OADDSTR {
                                r := r.(*ir.AddStringExpr)
-                               add.List.AppendNodes(&r.List)
+                               add.List.Append(r.List.Take()...)
                        } else {
                                add.List.Append(r)
                        }
                        base.Fatalf("need unsafe.Pointer for OSLICEHEADER")
                }
 
-               if x := n.LenCap.Len(); x != 2 {
+               if x := len(n.LenCap); x != 2 {
                        base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
                }
 
                n.Ptr = typecheck(n.Ptr, ctxExpr)
-               l := typecheck(n.LenCap.First(), ctxExpr)
-               c := typecheck(n.LenCap.Second(), ctxExpr)
+               l := typecheck(n.LenCap[0], ctxExpr)
+               c := typecheck(n.LenCap[1], ctxExpr)
                l = defaultlit(l, types.Types[types.TINT])
                c = defaultlit(c, types.Types[types.TINT])
 
                        base.Fatalf("len larger than cap for OSLICEHEADER")
                }
 
-               n.LenCap.SetFirst(l)
-               n.LenCap.SetSecond(c)
+               n.LenCap[0] = l
+               n.LenCap[1] = c
                return n
 
        case ir.OMAKESLICECOPY:
                if top == ctxStmt {
                        n.Use = ir.CallUseStmt
                }
-               typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
+               typecheckslice(n.Init(), ctxStmt) // imported rewritten f(g()) calls (#30907)
                n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee)
                if n.X.Diag() {
                        n.SetDiag(true)
                                        return n
                                }
                                u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
-                               return typecheck(initExpr(n.Init().Slice(), u), top) // typecheckargs can add to old.Init
+                               return typecheck(initExpr(n.Init(), u), top) // typecheckargs can add to old.Init
 
                        case ir.OCOMPLEX, ir.OCOPY:
                                typecheckargs(n)
                                        return n
                                }
                                b := ir.NewBinaryExpr(n.Pos(), l.BuiltinOp, arg1, arg2)
-                               return typecheck(initExpr(n.Init().Slice(), b), top) // typecheckargs can add to old.Init
+                               return typecheck(initExpr(n.Init(), b), top) // typecheckargs can add to old.Init
                        }
                        panic("unreachable")
                }
                n := n.(*ir.CallExpr)
                typecheckargs(n)
                args := n.Args
-               if args.Len() == 0 {
+               if len(args) == 0 {
                        base.Errorf("missing arguments to delete")
                        n.SetType(nil)
                        return n
                }
 
-               if args.Len() == 1 {
+               if len(args) == 1 {
                        base.Errorf("missing second (key) argument to delete")
                        n.SetType(nil)
                        return n
                }
 
-               if args.Len() != 2 {
+               if len(args) != 2 {
                        base.Errorf("too many arguments to delete")
                        n.SetType(nil)
                        return n
                }
 
-               l := args.First()
-               r := args.Second()
+               l := args[0]
+               r := args[1]
                if l.Type() != nil && !l.Type().IsMap() {
                        base.Errorf("first argument to delete must be map; have %L", l.Type())
                        n.SetType(nil)
                        return n
                }
 
-               args.SetSecond(assignconv(r, l.Type().Key(), "delete"))
+               args[1] = assignconv(r, l.Type().Key(), "delete")
                return n
 
        case ir.OAPPEND:
                n := n.(*ir.CallExpr)
                typecheckargs(n)
                args := n.Args
-               if args.Len() == 0 {
+               if len(args) == 0 {
                        base.Errorf("missing arguments to append")
                        n.SetType(nil)
                        return n
                }
 
-               t := args.First().Type()
+               t := args[0].Type()
                if t == nil {
                        n.SetType(nil)
                        return n
 
                n.SetType(t)
                if !t.IsSlice() {
-                       if ir.IsNil(args.First()) {
+                       if ir.IsNil(args[0]) {
                                base.Errorf("first argument to append must be typed slice; have untyped nil")
                                n.SetType(nil)
                                return n
                }
 
                if n.IsDDD {
-                       if args.Len() == 1 {
+                       if len(args) == 1 {
                                base.Errorf("cannot use ... on first argument to append")
                                n.SetType(nil)
                                return n
                        }
 
-                       if args.Len() != 2 {
+                       if len(args) != 2 {
                                base.Errorf("too many arguments to append")
                                n.SetType(nil)
                                return n
                        }
 
-                       if t.Elem().IsKind(types.TUINT8) && args.Second().Type().IsString() {
-                               args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING]))
+                       if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
+                               args[1] = defaultlit(args[1], types.Types[types.TSTRING])
                                return n
                        }
 
-                       args.SetSecond(assignconv(args.Second(), t.Underlying(), "append"))
+                       args[1] = assignconv(args[1], t.Underlying(), "append")
                        return n
                }
 
-               as := args.Slice()[1:]
+               as := args[1:]
                for i, n := range as {
                        if n.Type() == nil {
                                continue
 
        case ir.OMAKE:
                n := n.(*ir.CallExpr)
-               args := n.Args.Slice()
+               args := n.Args
                if len(args) == 0 {
                        base.Errorf("missing argument to make")
                        n.SetType(nil)
        case ir.OPRINT, ir.OPRINTN:
                n := n.(*ir.CallExpr)
                typecheckargs(n)
-               ls := n.Args.Slice()
+               ls := n.Args
                for i1, n1 := range ls {
                        // Special case for print: int constant is int64, not int.
                        if ir.IsConst(n1, constant.Int) {
 
        case ir.ORECOVER:
                n := n.(*ir.CallExpr)
-               if n.Args.Len() != 0 {
+               if len(n.Args) != 0 {
                        base.Errorf("too many arguments to recover")
                        n.SetType(nil)
                        return n
 
        case ir.OBLOCK:
                n := n.(*ir.BlockStmt)
-               typecheckslice(n.List.Slice(), ctxStmt)
+               typecheckslice(n.List, ctxStmt)
                return n
 
        case ir.OLABEL:
 
        case ir.OFOR, ir.OFORUNTIL:
                n := n.(*ir.ForStmt)
-               typecheckslice(n.Init().Slice(), ctxStmt)
+               typecheckslice(n.Init(), ctxStmt)
                decldepth++
                n.Cond = typecheck(n.Cond, ctxExpr)
                n.Cond = defaultlit(n.Cond, nil)
                }
                n.Post = typecheck(n.Post, ctxStmt)
                if n.Op() == ir.OFORUNTIL {
-                       typecheckslice(n.Late.Slice(), ctxStmt)
+                       typecheckslice(n.Late, ctxStmt)
                }
-               typecheckslice(n.Body.Slice(), ctxStmt)
+               typecheckslice(n.Body, ctxStmt)
                decldepth--
                return n
 
        case ir.OIF:
                n := n.(*ir.IfStmt)
-               typecheckslice(n.Init().Slice(), ctxStmt)
+               typecheckslice(n.Init(), ctxStmt)
                n.Cond = typecheck(n.Cond, ctxExpr)
                n.Cond = defaultlit(n.Cond, nil)
                if n.Cond != nil {
                                base.Errorf("non-bool %L used as if condition", n.Cond)
                        }
                }
-               typecheckslice(n.Body.Slice(), ctxStmt)
-               typecheckslice(n.Else.Slice(), ctxStmt)
+               typecheckslice(n.Body, ctxStmt)
+               typecheckslice(n.Else, ctxStmt)
                return n
 
        case ir.ORETURN:
                        return n
                }
 
-               if hasNamedResults(Curfn) && n.Results.Len() == 0 {
+               if hasNamedResults(Curfn) && len(n.Results) == 0 {
                        return n
                }
                typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.Results, func() string { return "return argument" })
        default:
                base.Fatalf("typecheckargs %+v", n.Op())
        case *ir.CallExpr:
-               list = n.Args.Slice()
+               list = n.Args
                if n.IsDDD {
                        typecheckslice(list, ctxExpr)
                        return
                }
        case *ir.ReturnStmt:
-               list = n.Results.Slice()
+               list = n.Results
        }
        if len(list) != 1 {
                typecheckslice(list, ctxExpr)
 }
 
 func needOneArg(n *ir.CallExpr, f string, args ...interface{}) (ir.Node, bool) {
-       if n.Args.Len() == 0 {
+       if len(n.Args) == 0 {
                p := fmt.Sprintf(f, args...)
                base.Errorf("missing argument to %s: %v", p, n)
                return nil, false
        }
 
-       if n.Args.Len() > 1 {
+       if len(n.Args) > 1 {
                p := fmt.Sprintf(f, args...)
                base.Errorf("too many arguments to %s: %v", p, n)
-               return n.Args.First(), false
+               return n.Args[0], false
        }
 
-       return n.Args.First(), true
+       return n.Args[0], true
 }
 
 func needTwoArgs(n *ir.CallExpr) (ir.Node, ir.Node, bool) {
-       if n.Args.Len() != 2 {
-               if n.Args.Len() < 2 {
+       if len(n.Args) != 2 {
+               if len(n.Args) < 2 {
                        base.Errorf("not enough arguments in call to %v", n)
                } else {
                        base.Errorf("too many arguments in call to %v", n)
                }
                return nil, nil, false
        }
-       return n.Args.First(), n.Args.Second(), true
+       return n.Args[0], n.Args[1], true
 }
 
 func lookdot1(errnode ir.Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
 }
 
 func nokeys(l ir.Nodes) bool {
-       for _, n := range l.Slice() {
+       for _, n := range l {
                if n.Op() == ir.OKEY || n.Op() == ir.OSTRUCTKEY {
                        return false
                }
        }
 
        var n ir.Node
-       if nl.Len() == 1 {
-               n = nl.First()
+       if len(nl) == 1 {
+               n = nl[0]
        }
 
        n1 := tstruct.NumFields()
-       n2 := nl.Len()
+       n2 := len(nl)
        if !hasddd(tstruct) {
                if n2 > n1 {
                        goto toomany
                t = tl.Type
                if tl.IsDDD() {
                        if isddd {
-                               if i >= nl.Len() {
+                               if i >= len(nl) {
                                        goto notenough
                                }
-                               if nl.Len()-i > 1 {
+                               if len(nl)-i > 1 {
                                        goto toomany
                                }
-                               n = nl.Index(i)
+                               n = nl[i]
                                setlineno(n)
                                if n.Type() != nil {
-                                       nl.SetIndex(i, assignconvfn(n, t, desc))
+                                       nl[i] = assignconvfn(n, t, desc)
                                }
                                return
                        }
 
                        // TODO(mdempsky): Make into ... call with implicit slice.
-                       for ; i < nl.Len(); i++ {
-                               n = nl.Index(i)
+                       for ; i < len(nl); i++ {
+                               n = nl[i]
                                setlineno(n)
                                if n.Type() != nil {
-                                       nl.SetIndex(i, assignconvfn(n, t.Elem(), desc))
+                                       nl[i] = assignconvfn(n, t.Elem(), desc)
                                }
                        }
                        return
                }
 
-               if i >= nl.Len() {
+               if i >= len(nl) {
                        goto notenough
                }
-               n = nl.Index(i)
+               n = nl[i]
                setlineno(n)
                if n.Type() != nil {
-                       nl.SetIndex(i, assignconvfn(n, t, desc))
+                       nl[i] = assignconvfn(n, t, desc)
                }
                i++
        }
 
-       if i < nl.Len() {
+       if i < len(nl) {
                goto toomany
        }
        if isddd {
                return ""
        }
        // If any node has an unknown type, suppress it as well
-       for _, n := range nl.Slice() {
+       for _, n := range nl {
                if n.Type() == nil {
                        return ""
                }
 
 // sigerr returns the signature of the types at the call or return.
 func fmtSignature(nl ir.Nodes, isddd bool) string {
-       if nl.Len() < 1 {
+       if len(nl) < 1 {
                return "()"
        }
 
        var typeStrings []string
-       for i, n := range nl.Slice() {
-               isdddArg := isddd && i == nl.Len()-1
+       for i, n := range nl {
+               isdddArg := isddd && i == len(nl)-1
                typeStrings = append(typeStrings, sigrepr(n.Type(), isdddArg))
        }
 
                        n.SetType(nil)
                        return n
                }
-               length := typecheckarraylit(elemType, -1, n.List.Slice(), "array literal")
+               length := typecheckarraylit(elemType, -1, n.List, "array literal")
                n.SetOp(ir.OARRAYLIT)
                n.SetType(types.NewArray(elemType, length))
                n.Ntype = nil
                n.SetType(nil)
 
        case types.TARRAY:
-               typecheckarraylit(t.Elem(), t.NumElem(), n.List.Slice(), "array literal")
+               typecheckarraylit(t.Elem(), t.NumElem(), n.List, "array literal")
                n.SetOp(ir.OARRAYLIT)
                n.Ntype = nil
 
        case types.TSLICE:
-               length := typecheckarraylit(t.Elem(), -1, n.List.Slice(), "slice literal")
+               length := typecheckarraylit(t.Elem(), -1, n.List, "slice literal")
                n.SetOp(ir.OSLICELIT)
                n.Ntype = nil
                n.Len = length
 
        case types.TMAP:
                var cs constSet
-               for i3, l := range n.List.Slice() {
+               for i3, l := range n.List {
                        setlineno(l)
                        if l.Op() != ir.OKEY {
-                               n.List.SetIndex(i3, typecheck(l, ctxExpr))
+                               n.List[i3] = typecheck(l, ctxExpr)
                                base.Errorf("missing key in map literal")
                                continue
                        }
                dowidth(t)
 
                errored := false
-               if n.List.Len() != 0 && nokeys(n.List) {
+               if len(n.List) != 0 && nokeys(n.List) {
                        // simple list of variables
-                       ls := n.List.Slice()
+                       ls := n.List
                        for i, n1 := range ls {
                                setlineno(n1)
                                n1 = typecheck(n1, ctxExpr)
                        hash := make(map[string]bool)
 
                        // keyed list
-                       ls := n.List.Slice()
+                       ls := n.List
                        for i, l := range ls {
                                setlineno(l)
 
 }
 
 func checkassignlist(stmt ir.Node, l ir.Nodes) {
-       for _, n := range l.Slice() {
+       for _, n := range l {
                checkassign(stmt, n)
        }
 }
                defer tracePrint("typecheckas2", n)(nil)
        }
 
-       ls := n.Lhs.Slice()
+       ls := n.Lhs
        for i1, n1 := range ls {
                // delicate little dance.
                n1 = resolve(n1)
                }
        }
 
-       cl := n.Lhs.Len()
-       cr := n.Rhs.Len()
+       cl := len(n.Lhs)
+       cr := len(n.Rhs)
        if cl > 1 && cr == 1 {
-               n.Rhs.SetFirst(typecheck(n.Rhs.First(), ctxExpr|ctxMultiOK))
+               n.Rhs[0] = typecheck(n.Rhs[0], ctxExpr|ctxMultiOK)
        } else {
-               typecheckslice(n.Rhs.Slice(), ctxExpr)
+               typecheckslice(n.Rhs, ctxExpr)
        }
        checkassignlist(n, n.Lhs)
 
        var r ir.Node
        if cl == cr {
                // easy
-               ls := n.Lhs.Slice()
-               rs := n.Rhs.Slice()
+               ls := n.Lhs
+               rs := n.Rhs
                for il, nl := range ls {
                        nr := rs[il]
                        if nl.Type() != nil && nr.Type() != nil {
                goto out
        }
 
-       l = n.Lhs.First()
-       r = n.Rhs.First()
+       l = n.Lhs[0]
+       r = n.Rhs[0]
 
        // x,y,z = f()
        if cr == 1 {
                        }
                        r.(*ir.CallExpr).Use = ir.CallUseList
                        n.SetOp(ir.OAS2FUNC)
-                       for i, l := range n.Lhs.Slice() {
+                       for i, l := range n.Lhs {
                                f := r.Type().Field(i)
                                if f.Type != nil && l.Type() != nil {
                                        checkassignto(f.Type, l)
                        if ir.DeclaredBy(l, n) {
                                l.SetType(r.Type())
                        }
-                       l := n.Lhs.Second()
+                       l := n.Lhs[1]
                        if l.Type() != nil && !l.Type().IsBoolean() {
                                checkassignto(types.Types[types.TBOOL], l)
                        }
        // second half of dance
 out:
        n.SetTypecheck(1)
-       ls = n.Lhs.Slice()
+       ls = n.Lhs
        for i1, n1 := range ls {
                if n1.Typecheck() == 0 {
                        ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
 
 // isTermNodes reports whether the Nodes list ends with a terminating statement.
 func isTermNodes(l ir.Nodes) bool {
-       s := l.Slice()
+       s := l
        c := len(s)
        if c == 0 {
                return false
                        return false
                }
                def := false
-               for _, cas := range n.Cases.Slice() {
+               for _, cas := range n.Cases {
                        cas := cas.(*ir.CaseStmt)
                        if !isTermNodes(cas.Body) {
                                return false
                        }
-                       if cas.List.Len() == 0 { // default
+                       if len(cas.List) == 0 { // default
                                def = true
                        }
                }
                if n.HasBreak {
                        return false
                }
-               for _, cas := range n.Cases.Slice() {
+               for _, cas := range n.Cases {
                        cas := cas.(*ir.CaseStmt)
                        if !isTermNodes(cas.Body) {
                                return false
 
 // checkreturn makes sure that fn terminates appropriately.
 func checkreturn(fn *ir.Func) {
-       if fn.Type().NumResults() != 0 && fn.Body.Len() != 0 {
+       if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
                markBreak(fn)
                if !isTermNodes(fn.Body) {
                        base.ErrorfAt(fn.Endlineno, "missing return at end of function")
 func deadcode(fn *ir.Func) {
        deadcodeslice(&fn.Body)
 
-       if fn.Body.Len() == 0 {
+       if len(fn.Body) == 0 {
                return
        }
 
-       for _, n := range fn.Body.Slice() {
-               if n.Init().Len() > 0 {
+       for _, n := range fn.Body {
+               if len(n.Init()) > 0 {
                        return
                }
                switch n.Op() {
                case ir.OIF:
                        n := n.(*ir.IfStmt)
-                       if !ir.IsConst(n.Cond, constant.Bool) || n.Body.Len() > 0 || n.Else.Len() > 0 {
+                       if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
                                return
                        }
                case ir.OFOR:
 
 func deadcodeslice(nn *ir.Nodes) {
        var lastLabel = -1
-       for i, n := range nn.Slice() {
+       for i, n := range *nn {
                if n != nil && n.Op() == ir.OLABEL {
                        lastLabel = i
                }
        }
-       for i, n := range nn.Slice() {
+       for i, n := range *nn {
                // Cut is set to true when all nodes after i'th position
                // should be removed.
                // In other words, it marks whole slice "tail" as dead.
                                // isterminating is not used to avoid goto-related complications.
                                // We must be careful not to deadcode-remove labels, as they
                                // might be the target of a goto. See issue 28616.
-                               if body := body.Slice(); len(body) != 0 {
+                               if body := body; len(body) != 0 {
                                        switch body[(len(body) - 1)].Op() {
                                        case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
                                                if i > lastLabel {
                }
 
                if cut {
-                       nn.Set(nn.Slice()[:i+1])
+                       nn.Set((*nn)[:i+1])
                        break
                }
        }
 
        if base.Errors() > errorsBefore {
                return
        }
-       walkstmtlist(Curfn.Body.Slice())
+       walkstmtlist(Curfn.Body)
        if base.Flag.W != 0 {
                s := fmt.Sprintf("after walk %v", Curfn.Sym())
                ir.DumpList(s, Curfn.Body)
 
        zeroResults()
        heapmoves()
-       if base.Flag.W != 0 && Curfn.Enter.Len() > 0 {
+       if base.Flag.W != 0 && len(Curfn.Enter) > 0 {
                s := fmt.Sprintf("enter %v", Curfn.Sym())
                ir.DumpList(s, Curfn.Enter)
        }
 
        setlineno(n)
 
-       walkstmtlist(n.Init().Slice())
+       walkstmtlist(n.Init())
 
        switch n.Op() {
        default:
                if n.Op() == ir.ONAME {
                        // copy rewrote to a statement list and a temp for the length.
                        // Throw away the temp to avoid plain values as statements.
-                       n = ir.NewBlockStmt(n.Pos(), init.Slice())
+                       n = ir.NewBlockStmt(n.Pos(), init)
                        init.Set(nil)
                }
-               if init.Len() > 0 {
+               if len(init) > 0 {
                        switch n.Op() {
                        case ir.OAS, ir.OAS2, ir.OBLOCK:
-                               n.PtrInit().Prepend(init.Slice()...)
+                               n.PtrInit().Prepend(init...)
 
                        default:
                                init.Append(n)
-                               n = ir.NewBlockStmt(n.Pos(), init.Slice())
+                               n = ir.NewBlockStmt(n.Pos(), init)
                        }
                }
                return n
 
                n.X = walkexpr(n.X, &init)
                call := walkexpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, nodnil()), &init)
-               return initExpr(init.Slice(), call)
+               return initExpr(init, call)
 
        case ir.OBREAK,
                ir.OCONTINUE,
 
        case ir.OBLOCK:
                n := n.(*ir.BlockStmt)
-               walkstmtlist(n.List.Slice())
+               walkstmtlist(n.List)
                return n
 
        case ir.OCASE:
 
                case ir.ODELETE:
                        call := call.(*ir.CallExpr)
-                       if mapfast(call.Args.First().Type()) == mapslow {
+                       if mapfast(call.Args[0].Type()) == mapslow {
                                n.Call = wrapCall(call, &init)
                        } else {
                                n.Call = walkexpr(call, &init)
 
                case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
                        call := call.(*ir.CallExpr)
-                       if call.Body.Len() > 0 {
+                       if len(call.Body) > 0 {
                                n.Call = wrapCall(call, &init)
                        } else {
                                n.Call = walkexpr(call, &init)
                default:
                        n.Call = walkexpr(call, &init)
                }
-               if init.Len() > 0 {
+               if len(init) > 0 {
                        init.Append(n)
-                       return ir.NewBlockStmt(n.Pos(), init.Slice())
+                       return ir.NewBlockStmt(n.Pos(), init)
                }
                return n
 
        case ir.OFOR, ir.OFORUNTIL:
                n := n.(*ir.ForStmt)
                if n.Cond != nil {
-                       walkstmtlist(n.Cond.Init().Slice())
+                       walkstmtlist(n.Cond.Init())
                        init := n.Cond.Init()
                        n.Cond.PtrInit().Set(nil)
                        n.Cond = walkexpr(n.Cond, &init)
-                       n.Cond = initExpr(init.Slice(), n.Cond)
+                       n.Cond = initExpr(init, n.Cond)
                }
 
                n.Post = walkstmt(n.Post)
                if n.Op() == ir.OFORUNTIL {
-                       walkstmtlist(n.Late.Slice())
+                       walkstmtlist(n.Late)
                }
-               walkstmtlist(n.Body.Slice())
+               walkstmtlist(n.Body)
                return n
 
        case ir.OIF:
                n := n.(*ir.IfStmt)
                n.Cond = walkexpr(n.Cond, n.PtrInit())
-               walkstmtlist(n.Body.Slice())
-               walkstmtlist(n.Else.Slice())
+               walkstmtlist(n.Body)
+               walkstmtlist(n.Else)
                return n
 
        case ir.ORETURN:
                n := n.(*ir.ReturnStmt)
                Curfn.NumReturns++
-               if n.Results.Len() == 0 {
+               if len(n.Results) == 0 {
                        return n
                }
-               if (hasNamedResults(Curfn) && n.Results.Len() > 1) || paramoutheap(Curfn) {
+               if (hasNamedResults(Curfn) && len(n.Results) > 1) || paramoutheap(Curfn) {
                        // assign to the function out parameters,
                        // so that ascompatee can fix up conflicts
                        var rl []ir.Node
                                }
                        }
 
-                       if got, want := n.Results.Len(), len(rl); got != want {
+                       if got, want := len(n.Results), len(rl); got != want {
                                // order should have rewritten multi-value function calls
                                // with explicit OAS2FUNC nodes.
                                base.Fatalf("expected %v return arguments, have %v", want, got)
                        }
 
                        // move function calls out, to make ascompatee's job easier.
-                       walkexprlistsafe(n.Results.Slice(), n.PtrInit())
+                       walkexprlistsafe(n.Results, n.PtrInit())
 
-                       n.Results.Set(ascompatee(n.Op(), rl, n.Results.Slice(), n.PtrInit()))
+                       n.Results.Set(ascompatee(n.Op(), rl, n.Results, n.PtrInit()))
                        return n
                }
-               walkexprlist(n.Results.Slice(), n.PtrInit())
+               walkexprlist(n.Results, n.PtrInit())
 
                // For each return parameter (lhs), assign the corresponding result (rhs).
                lhs := Curfn.Type().Results()
-               rhs := n.Results.Slice()
+               rhs := n.Results
                res := make([]ir.Node, lhs.NumFields())
                for i, nl := range lhs.FieldSlice() {
                        nname := ir.AsNode(nl.Nname)
                base.Fatalf("walkexpr init == &n->ninit")
        }
 
-       if n.Init().Len() != 0 {
-               walkstmtlist(n.Init().Slice())
-               init.AppendNodes(n.PtrInit())
+       if len(n.Init()) != 0 {
+               walkstmtlist(n.Init())
+               init.Append(n.PtrInit().Take()...)
        }
 
        lno := setlineno(n)
                        n.Ntype.(*ir.AddrExpr).Alloc = typename(n.X.Type())
                }
                if !n.Type().IsInterface() && !n.X.Type().IsEmptyInterface() {
-                       n.Itab.Set1(itabname(n.Type(), n.X.Type()))
+                       n.Itab = []ir.Node{itabname(n.Type(), n.X.Type())}
                }
                return n
 
                var ll ir.Nodes
 
                n.Y = walkexpr(n.Y, &ll)
-               n.Y = initExpr(ll.Slice(), n.Y)
+               n.Y = initExpr(ll, n.Y)
                return n
 
        case ir.OPRINT, ir.OPRINTN:
 
                        // Prepend captured variables to argument list.
                        clo := n.X.(*ir.ClosureExpr)
-                       n.Args.Prepend(clo.Func.ClosureEnter.Slice()...)
+                       n.Args.Prepend(clo.Func.ClosureEnter...)
                        clo.Func.ClosureEnter.Set(nil)
 
                        // Replace OCLOSURE with ONAME/PFUNC.
                return n
 
        case ir.OAS, ir.OASOP:
-               init.AppendNodes(n.PtrInit())
+               init.Append(n.PtrInit().Take()...)
 
                var left, right ir.Node
                switch n.Op() {
                if left.Op() == ir.OINDEXMAP && right.Op() == ir.OAPPEND {
                        left := left.(*ir.IndexExpr)
                        mapAppend = right.(*ir.CallExpr)
-                       if !samesafeexpr(left, mapAppend.Args.First()) {
-                               base.Fatalf("not same expressions: %v != %v", left, mapAppend.Args.First())
+                       if !samesafeexpr(left, mapAppend.Args[0]) {
+                               base.Fatalf("not same expressions: %v != %v", left, mapAppend.Args[0])
                        }
                }
 
                left = walkexpr(left, init)
                left = safeexpr(left, init)
                if mapAppend != nil {
-                       mapAppend.Args.SetFirst(left)
+                       mapAppend.Args[0] = left
                }
 
                if n.Op() == ir.OASOP {
 
        case ir.OAS2:
                n := n.(*ir.AssignListStmt)
-               init.AppendNodes(n.PtrInit())
-               walkexprlistsafe(n.Lhs.Slice(), init)
-               walkexprlistsafe(n.Rhs.Slice(), init)
-               return liststmt(ascompatee(ir.OAS, n.Lhs.Slice(), n.Rhs.Slice(), init))
+               init.Append(n.PtrInit().Take()...)
+               walkexprlistsafe(n.Lhs, init)
+               walkexprlistsafe(n.Rhs, init)
+               return liststmt(ascompatee(ir.OAS, n.Lhs, n.Rhs, init))
 
        // a,b,... = fn()
        case ir.OAS2FUNC:
                n := n.(*ir.AssignListStmt)
-               init.AppendNodes(n.PtrInit())
+               init.Append(n.PtrInit().Take()...)
 
-               r := n.Rhs.First()
-               walkexprlistsafe(n.Lhs.Slice(), init)
+               r := n.Rhs[0]
+               walkexprlistsafe(n.Lhs, init)
                r = walkexpr(r, init)
 
                if IsIntrinsicCall(r.(*ir.CallExpr)) {
-                       n.Rhs.Set1(r)
+                       n.Rhs = []ir.Node{r}
                        return n
                }
                init.Append(r)
        // order.stmt made sure x is addressable or blank.
        case ir.OAS2RECV:
                n := n.(*ir.AssignListStmt)
-               init.AppendNodes(n.PtrInit())
+               init.Append(n.PtrInit().Take()...)
 
-               r := n.Rhs.First().(*ir.UnaryExpr) // recv
-               walkexprlistsafe(n.Lhs.Slice(), init)
+               r := n.Rhs[0].(*ir.UnaryExpr) // recv
+               walkexprlistsafe(n.Lhs, init)
                r.X = walkexpr(r.X, init)
                var n1 ir.Node
-               if ir.IsBlank(n.Lhs.First()) {
+               if ir.IsBlank(n.Lhs[0]) {
                        n1 = nodnil()
                } else {
-                       n1 = nodAddr(n.Lhs.First())
+                       n1 = nodAddr(n.Lhs[0])
                }
                fn := chanfn("chanrecv2", 2, r.X.Type())
-               ok := n.Lhs.Second()
+               ok := n.Lhs[1]
                call := mkcall1(fn, types.Types[types.TBOOL], init, r.X, n1)
                return typecheck(ir.NewAssignStmt(base.Pos, ok, call), ctxStmt)
 
        // a,b = m[i]
        case ir.OAS2MAPR:
                n := n.(*ir.AssignListStmt)
-               init.AppendNodes(n.PtrInit())
+               init.Append(n.PtrInit().Take()...)
 
-               r := n.Rhs.First().(*ir.IndexExpr)
-               walkexprlistsafe(n.Lhs.Slice(), init)
+               r := n.Rhs[0].(*ir.IndexExpr)
+               walkexprlistsafe(n.Lhs, init)
                r.X = walkexpr(r.X, init)
                r.Index = walkexpr(r.Index, init)
                t := r.X.Type()
                // to:
                //   var,b = mapaccess2*(t, m, i)
                //   a = *var
-               a := n.Lhs.First()
+               a := n.Lhs[0]
 
                var call *ir.CallExpr
                if w := t.Elem().Width; w <= zeroValSize {
                // mapaccess2* returns a typed bool, but due to spec changes,
                // the boolean result of i.(T) is now untyped so we make it the
                // same type as the variable on the lhs.
-               if ok := n.Lhs.Second(); !ir.IsBlank(ok) && ok.Type().IsBoolean() {
+               if ok := n.Lhs[1]; !ir.IsBlank(ok) && ok.Type().IsBoolean() {
                        call.Type().Field(1).Type = ok.Type()
                }
-               n.Rhs.Set1(call)
+               n.Rhs = []ir.Node{call}
                n.SetOp(ir.OAS2FUNC)
 
                // don't generate a = *var if a is _
                var_.SetTypecheck(1)
                var_.MarkNonNil() // mapaccess always returns a non-nil pointer
 
-               n.Lhs.SetFirst(var_)
+               n.Lhs[0] = var_
                init.Append(walkexpr(n, init))
 
                as := ir.NewAssignStmt(base.Pos, a, ir.NewStarExpr(base.Pos, var_))
 
        case ir.ODELETE:
                n := n.(*ir.CallExpr)
-               init.AppendNodes(n.PtrInit())
-               map_ := n.Args.First()
-               key := n.Args.Second()
+               init.Append(n.PtrInit().Take()...)
+               map_ := n.Args[0]
+               key := n.Args[1]
                map_ = walkexpr(map_, init)
                key = walkexpr(key, init)
 
 
        case ir.OAS2DOTTYPE:
                n := n.(*ir.AssignListStmt)
-               walkexprlistsafe(n.Lhs.Slice(), init)
-               (&n.Rhs).SetIndex(0, walkexpr(n.Rhs.First(), init))
+               walkexprlistsafe(n.Lhs, init)
+               n.Rhs[0] = walkexpr(n.Rhs[0], init)
                return n
 
        case ir.OCONVIFACE:
 
                        // Get the type out of the itab.
                        nif := ir.NewIfStmt(base.Pos, typecheck(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, nodnil()), ctxExpr), nil, nil)
-                       nif.Body.Set1(ir.NewAssignStmt(base.Pos, tmp, itabType(tmp)))
+                       nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, tmp, itabType(tmp))}
                        init.Append(nif)
 
                        // Build the result.
                        fn = substArgTypes(fn, fromType)
                        dowidth(fn.Type())
                        call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
-                       call.Args.Set1(n.X)
+                       call.Args = []ir.Node{n.X}
                        e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeexpr(walkexpr(typecheck(call, ctxExpr), init), init))
                        e.SetType(toType)
                        e.SetTypecheck(1)
                fn = substArgTypes(fn, fromType, toType)
                dowidth(fn.Type())
                call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
-               call.Args.Set2(tab, v)
+               call.Args = []ir.Node{tab, v}
                return walkexpr(typecheck(call, ctxExpr), init)
 
        case ir.OCONV, ir.OCONVNOP:
        case ir.OSLICEHEADER:
                n := n.(*ir.SliceHeaderExpr)
                n.Ptr = walkexpr(n.Ptr, init)
-               n.LenCap.SetFirst(walkexpr(n.LenCap.First(), init))
-               n.LenCap.SetSecond(walkexpr(n.LenCap.Second(), init))
+               n.LenCap[0] = walkexpr(n.LenCap[0], init)
+               n.LenCap[1] = walkexpr(n.LenCap[1], init)
                return n
 
        case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
                        // }
                        nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, conv(l, types.Types[types.TUINT64]), nodintconst(i)), nil, nil)
                        niflen := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, l, nodintconst(0)), nil, nil)
-                       niflen.Body.Set1(mkcall("panicmakeslicelen", nil, init))
+                       niflen.Body = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
                        nif.Body.Append(niflen, mkcall("panicmakeslicecap", nil, init))
                        init.Append(typecheck(nif, ctxStmt))
 
                fn := syslook(fnname)
                m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
                m.Ptr.MarkNonNil()
-               m.LenCap.Set2(conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT]))
+               m.LenCap = []ir.Node{conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT])}
                return walkexpr(typecheck(m, ctxExpr), init)
 
        case ir.OMAKESLICECOPY:
                        sh := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
                        sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, nodnil(), nodbool(false))
                        sh.Ptr.MarkNonNil()
-                       sh.LenCap.Set2(length, length)
+                       sh.LenCap = []ir.Node{length, length}
                        sh.SetType(t)
 
                        s := temp(t)
                s := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
                s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[types.TUNSAFEPTR]))
                s.Ptr.MarkNonNil()
-               s.LenCap.Set2(length, length)
+               s.LenCap = []ir.Node{length, length}
                s.SetType(t)
                return walkexpr(typecheck(s, ctxExpr), init)
 
 // an expression list. called in
 //     expr-list = func()
 func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node {
-       if nl.Len() != nr.NumFields() {
-               base.Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
+       if len(nl) != nr.NumFields() {
+               base.Fatalf("ascompatet: assignment count mismatch: %d = %d", len(nl), nr.NumFields())
        }
 
        var nn, mm ir.Nodes
-       for i, l := range nl.Slice() {
+       for i, l := range nl {
                if ir.IsBlank(l) {
                        continue
                }
 
                nn.Append(a)
        }
-       return append(nn.Slice(), mm.Slice()...)
+       return append(nn, mm...)
 }
 
 // package all the arguments that match a ... T parameter into a []T.
        vi := fntype.NumParams() - 1
        vt := fntype.Params().Field(vi).Type
 
-       args := call.Args.Slice()
+       args := call.Args
        extra := args[vi:]
        slice := mkdotargslice(vt, extra)
        for i := range extra {
 }
 
 func walkCall(n *ir.CallExpr, init *ir.Nodes) {
-       if n.Rargs.Len() != 0 {
+       if len(n.Rargs) != 0 {
                return // already walked
        }
 
        params := n.X.Type().Params()
-       args := n.Args.Slice()
+       args := n.Args
 
        n.X = walkexpr(n.X, init)
        walkexprlist(args, init)
 // generate code for print
 func walkprint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
        // Hoist all the argument evaluation up before the lock.
-       walkexprlistcheap(nn.Args.Slice(), init)
+       walkexprlistcheap(nn.Args, init)
 
        // For println, add " " between elements and "\n" at the end.
        if nn.Op() == ir.OPRINTN {
-               s := nn.Args.Slice()
+               s := nn.Args
                t := make([]ir.Node, 0, len(s)*2)
                for i, n := range s {
                        if i != 0 {
        }
 
        // Collapse runs of constant strings.
-       s := nn.Args.Slice()
+       s := nn.Args
        t := make([]ir.Node, 0, len(s))
        for i := 0; i < len(s); {
                var strs []string
        nn.Args.Set(t)
 
        calls := []ir.Node{mkcall("printlock", nil, init)}
-       for i, n := range nn.Args.Slice() {
+       for i, n := range nn.Args {
                if n.Op() == ir.OLITERAL {
                        if n.Type() == types.UntypedRune {
                                n = defaultlit(n, types.RuneType)
                        n = defaultlit(n, types.Types[types.TINT64])
                }
                n = defaultlit(n, nil)
-               nn.Args.SetIndex(i, n)
+               nn.Args[i] = n
                if n.Type() == nil || n.Type().Kind() == types.TFORW {
                        continue
                }
                all[i].Y = reorder3save(all[i].Y, all, i, &early)
        }
 
-       early = append(mapinit.Slice(), early...)
+       early = append(mapinit, early...)
        for _, as := range all {
                early = append(early, as)
        }
 }
 
 func addstr(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
-       c := n.List.Len()
+       c := len(n.List)
 
        if c < 2 {
                base.Fatalf("addstr count %d too small", c)
        buf := nodnil()
        if n.Esc() == EscNone {
                sz := int64(0)
-               for _, n1 := range n.List.Slice() {
+               for _, n1 := range n.List {
                        if n1.Op() == ir.OLITERAL {
                                sz += int64(len(ir.StringVal(n1)))
                        }
 
        // build list of string arguments
        args := []ir.Node{buf}
-       for _, n2 := range n.List.Slice() {
+       for _, n2 := range n.List {
                args = append(args, conv(n2, types.Types[types.TSTRING]))
        }
 
 }
 
 func walkAppendArgs(n *ir.CallExpr, init *ir.Nodes) {
-       walkexprlistsafe(n.Args.Slice(), init)
+       walkexprlistsafe(n.Args, init)
 
        // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
        // and n are name or literal, but those may index the slice we're
        // modifying here. Fix explicitly.
-       ls := n.Args.Slice()
+       ls := n.Args
        for i1, n1 := range ls {
                ls[i1] = cheapexpr(n1, init)
        }
 func appendslice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
        walkAppendArgs(n, init)
 
-       l1 := n.Args.First()
-       l2 := n.Args.Second()
+       l1 := n.Args[0]
+       l2 := n.Args[1]
        l2 = cheapexpr(l2, init)
-       n.Args.SetSecond(l2)
+       n.Args[1] = l2
 
        var nodes ir.Nodes
 
        fn = substArgTypes(fn, elemtype, elemtype)
 
        // s = growslice(T, s, n)
-       nif.Body.Set1(ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn)))
+       nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
        nodes.Append(nif)
 
        // s = s[:n]
                fn = substArgTypes(fn, elemtype, elemtype)
                ncopy = mkcall1(fn, nil, &nodes, addr, sptr, nwid)
        }
-       ln := append(nodes.Slice(), ncopy)
+       ln := append(nodes, ncopy)
 
        typecheckslice(ln, ctxStmt)
        walkstmtlist(ln)
                return false
        }
        call := n.(*ir.CallExpr)
-       if !call.IsDDD || call.Args.Len() != 2 || call.Args.Second().Op() != ir.OMAKESLICE {
+       if !call.IsDDD || len(call.Args) != 2 || call.Args[1].Op() != ir.OMAKESLICE {
                return false
        }
 
-       mk := call.Args.Second().(*ir.MakeExpr)
+       mk := call.Args[1].(*ir.MakeExpr)
        if mk.Cap != nil {
                return false
        }
        // isAppendOfMake made sure all possible positive values of l2 fit into an uint.
        // The case of l2 overflow when converting from e.g. uint to int is handled by an explicit
        // check of l2 < 0 at runtime which is generated below.
-       l2 := conv(n.Args.Second().(*ir.MakeExpr).Len, types.Types[types.TINT])
+       l2 := conv(n.Args[1].(*ir.MakeExpr).Len, types.Types[types.TINT])
        l2 = typecheck(l2, ctxExpr)
-       n.Args.SetSecond(l2) // walkAppendArgs expects l2 in n.List.Second().
+       n.Args[1] = l2 // walkAppendArgs expects l2 in n.List.Second().
 
        walkAppendArgs(n, init)
 
-       l1 := n.Args.First()
-       l2 = n.Args.Second() // re-read l2, as it may have been updated by walkAppendArgs
+       l1 := n.Args[0]
+       l2 = n.Args[1] // re-read l2, as it may have been updated by walkAppendArgs
 
        var nodes []ir.Node
 
        nifneg.Likely = true
 
        // else panicmakeslicelen()
-       nifneg.Else.Set1(mkcall("panicmakeslicelen", nil, init))
+       nifneg.Else = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
        nodes = append(nodes, nifneg)
 
        // s := l1
        fn = substArgTypes(fn, elemtype, elemtype)
 
        // s = growslice(T, s, n)
-       nif.Body.Set1(ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn)))
+       nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
        nodes = append(nodes, nif)
 
        // s = s[:n]
                nifclr.Body = clr
                nodes = append(nodes, nifclr)
        } else {
-               nodes = append(nodes, clr.Slice()...)
+               nodes = append(nodes, clr...)
        }
 
        typecheckslice(nodes, ctxStmt)
 //   }
 //   s
 func walkappend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
-       if !samesafeexpr(dst, n.Args.First()) {
-               n.Args.SetFirst(safeexpr(n.Args.First(), init))
-               n.Args.SetFirst(walkexpr(n.Args.First(), init))
+       if !samesafeexpr(dst, n.Args[0]) {
+               n.Args[0] = safeexpr(n.Args[0], init)
+               n.Args[0] = walkexpr(n.Args[0], init)
        }
-       walkexprlistsafe(n.Args.Slice()[1:], init)
+       walkexprlistsafe(n.Args[1:], init)
 
-       nsrc := n.Args.First()
+       nsrc := n.Args[0]
 
        // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
        // and n are name or literal, but those may index the slice we're
        // Using cheapexpr also makes sure that the evaluation
        // of all arguments (and especially any panics) happen
        // before we begin to modify the slice in a visible way.
-       ls := n.Args.Slice()[1:]
+       ls := n.Args[1:]
        for i, n := range ls {
                n = cheapexpr(n, init)
                if !types.Identical(n.Type(), nsrc.Type().Elem()) {
                ls[i] = n
        }
 
-       argc := n.Args.Len() - 1
+       argc := len(n.Args) - 1
        if argc < 1 {
                return nsrc
        }
        fn := syslook("growslice") //   growslice(<type>, old []T, mincap int) (ret []T)
        fn = substArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
 
-       nif.Body.Set1(ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), typename(ns.Type().Elem()), ns,
-               ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns), na))))
+       nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), typename(ns.Type().Elem()), ns,
+               ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns), na)))}
 
        l = append(l, nif)
 
        slice.SetBounded(true)
        l = append(l, ir.NewAssignStmt(base.Pos, ns, slice)) // s = s[:n+argc]
 
-       ls = n.Args.Slice()[1:]
+       ls = n.Args[1:]
        for i, n := range ls {
                ix := ir.NewIndexExpr(base.Pos, ns, nn) // s[n] ...
                ix.SetBounded(true)
 // The result of wrapCall MUST be assigned back to n, e.g.
 //     n.Left = wrapCall(n.Left, init)
 func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
-       if n.Init().Len() != 0 {
-               walkstmtlist(n.Init().Slice())
-               init.AppendNodes(n.PtrInit())
+       if len(n.Init()) != 0 {
+               walkstmtlist(n.Init())
+               init.Append(n.PtrInit().Take()...)
        }
 
        isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
 
        // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
        if !isBuiltinCall && n.IsDDD {
-               last := n.Args.Len() - 1
-               if va := n.Args.Index(last); va.Op() == ir.OSLICELIT {
+               last := len(n.Args) - 1
+               if va := n.Args[last]; va.Op() == ir.OSLICELIT {
                        va := va.(*ir.CompLitExpr)
-                       n.Args.Set(append(n.Args.Slice()[:last], va.List.Slice()...))
+                       n.Args.Set(append(n.Args[:last], va.List...))
                        n.IsDDD = false
                }
        }
 
        // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
-       origArgs := make([]ir.Node, n.Args.Len())
+       origArgs := make([]ir.Node, len(n.Args))
        var funcArgs []*ir.Field
-       for i, arg := range n.Args.Slice() {
+       for i, arg := range n.Args {
                s := lookupN("a", i)
                if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
                        origArgs[i] = arg
                        arg = arg.(*ir.ConvExpr).X
-                       n.Args.SetIndex(i, arg)
+                       n.Args[i] = arg
                }
                funcArgs = append(funcArgs, symfield(s, arg.Type()))
        }
                call.SetOp(ir.OCALL)
                call.IsDDD = n.IsDDD
        }
-       fn.Body.Set1(call)
+       fn.Body = []ir.Node{call}
 
        funcbody()
 
        typecheckFunc(fn)
-       typecheckslice(fn.Body.Slice(), ctxStmt)
+       typecheckslice(fn.Body, ctxStmt)
        Target.Decls = append(Target.Decls, fn)
 
-       call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.Args.Slice())
+       call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.Args)
        return walkexpr(typecheck(call, ctxStmt), init)
 }
 
 
                                        omitted = true
                                        continue // exclude zero-valued fields
                                }
-                               if n, ok := x.Interface().(Nodes); ok && n.Len() == 0 {
+                               if n, ok := x.Interface().(Nodes); ok && len(n) == 0 {
                                        omitted = true
                                        continue // exclude empty Nodes slices
                                }
 
 // SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
 // n must be a slice expression. max is nil if n is a simple slice expression.
 func (n *SliceExpr) SliceBounds() (low, high, max Node) {
-       if n.List.Len() == 0 {
+       if len(n.List) == 0 {
                return nil, nil, nil
        }
 
        switch n.Op() {
        case OSLICE, OSLICEARR, OSLICESTR:
-               s := n.List.Slice()
+               s := n.List
                return s[0], s[1], nil
        case OSLICE3, OSLICE3ARR:
-               s := n.List.Slice()
+               s := n.List
                return s[0], s[1], s[2]
        }
        base.Fatalf("SliceBounds op %v: %v", n.Op(), n)
                if max != nil {
                        base.Fatalf("SetSliceBounds %v given three bounds", n.Op())
                }
-               s := n.List.Slice()
+               s := n.List
                if s == nil {
                        if low == nil && high == nil {
                                return
                        }
-                       n.List.Set2(low, high)
+                       n.List = []Node{low, high}
                        return
                }
                s[0] = low
                s[1] = high
                return
        case OSLICE3, OSLICE3ARR:
-               s := n.List.Slice()
+               s := n.List
                if s == nil {
                        if low == nil && high == nil && max == nil {
                                return
                        }
-                       n.List.Set3(low, high, max)
+                       n.List = []Node{low, high, max}
                        return
                }
                s[0] = low
        n.pos = pos
        n.op = OSLICEHEADER
        n.typ = typ
-       n.LenCap.Set2(len, cap)
+       n.LenCap = []Node{len, cap}
        return n
 }
 
 
        // block starting with the init statements.
 
        // if we can just say "for" n->ninit; ... then do so
-       simpleinit := n.Init().Len() == 1 && n.Init().First().Init().Len() == 0 && StmtWithInit(n.Op())
+       simpleinit := len(n.Init()) == 1 && len(n.Init()[0].Init()) == 0 && StmtWithInit(n.Op())
 
        // otherwise, print the inits as separate statements
-       complexinit := n.Init().Len() != 0 && !simpleinit && exportFormat
+       complexinit := len(n.Init()) != 0 && !simpleinit && exportFormat
 
        // but if it was for if/for/switch, put in an extra surrounding block to limit the scope
        extrablock := complexinit && StmtWithInit(n.Op())
 
        case OBLOCK:
                n := n.(*BlockStmt)
-               if n.List.Len() != 0 {
+               if len(n.List) != 0 {
                        fmt.Fprintf(s, "%v", n.List)
                }
 
        case OIF:
                n := n.(*IfStmt)
                if simpleinit {
-                       fmt.Fprintf(s, "if %v; %v { %v }", n.Init().First(), n.Cond, n.Body)
+                       fmt.Fprintf(s, "if %v; %v { %v }", n.Init()[0], n.Cond, n.Body)
                } else {
                        fmt.Fprintf(s, "if %v { %v }", n.Cond, n.Body)
                }
-               if n.Else.Len() != 0 {
+               if len(n.Else) != 0 {
                        fmt.Fprintf(s, " else { %v }", n.Else)
                }
 
 
                fmt.Fprint(s, opname)
                if simpleinit {
-                       fmt.Fprintf(s, " %v;", n.Init().First())
+                       fmt.Fprintf(s, " %v;", n.Init()[0])
                } else if n.Post != nil {
                        fmt.Fprint(s, " ;")
                }
                        fmt.Fprint(s, ";")
                }
 
-               if n.Op() == OFORUNTIL && n.Late.Len() != 0 {
+               if n.Op() == OFORUNTIL && len(n.Late) != 0 {
                        fmt.Fprintf(s, "; %v", n.Late)
                }
 
                        break
                }
 
-               if n.Vars.Len() == 0 {
+               if len(n.Vars) == 0 {
                        fmt.Fprintf(s, "for range %v { %v }", n.X, n.Body)
                        break
                }
                }
                fmt.Fprintf(s, "switch")
                if simpleinit {
-                       fmt.Fprintf(s, " %v;", n.Init().First())
+                       fmt.Fprintf(s, " %v;", n.Init()[0])
                }
                if n.Tag != nil {
                        fmt.Fprintf(s, " %v ", n.Tag)
 
        case OCASE:
                n := n.(*CaseStmt)
-               if n.List.Len() != 0 {
+               if len(n.List) != 0 {
                        fmt.Fprintf(s, "case %.v", n.List)
                } else {
                        fmt.Fprint(s, "default")
                                return
                        }
                        if n.Ntype != nil {
-                               fmt.Fprintf(s, "%v{%s}", n.Ntype, ellipsisIf(n.List.Len() != 0))
+                               fmt.Fprintf(s, "%v{%s}", n.Ntype, ellipsisIf(len(n.List) != 0))
                                return
                        }
 
        case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
                n := n.(*CompLitExpr)
                if !exportFormat {
-                       fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(n.List.Len() != 0))
+                       fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(len(n.List) != 0))
                        return
                }
                fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List)
 
        case OSLICEHEADER:
                n := n.(*SliceHeaderExpr)
-               if n.LenCap.Len() != 2 {
-                       base.Fatalf("bad OSLICEHEADER list length %d", n.LenCap.Len())
+               if len(n.LenCap) != 2 {
+                       base.Fatalf("bad OSLICEHEADER list length %d", len(n.LenCap))
                }
-               fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.LenCap.First(), n.LenCap.Second())
+               fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.LenCap[0], n.LenCap[1])
 
        case OCOMPLEX, OCOPY:
                n := n.(*BinaryExpr)
 
        case OADDSTR:
                n := n.(*AddStringExpr)
-               for i, n1 := range n.List.Slice() {
+               for i, n1 := range n.List {
                        if i != 0 {
                                fmt.Fprint(s, " + ")
                        }
                sep = ", "
        }
 
-       for i, n := range l.Slice() {
+       for i, n := range l {
                fmt.Fprint(s, n)
-               if i+1 < l.Len() {
+               if i+1 < len(l) {
                        fmt.Fprint(s, sep)
                }
        }
                return
        }
 
-       if n.Init().Len() != 0 {
+       if len(n.Init()) != 0 {
                fmt.Fprintf(w, "%+v-init", n.Op())
                dumpNodes(w, n.Init(), depth+1)
                indent(w, depth)
                                dumpNode(w, dcl, depth+1)
                        }
                }
-               if fn.Body.Len() > 0 {
+               if len(fn.Body) > 0 {
                        indent(w, depth)
                        fmt.Fprintf(w, "%+v-body", n.Op())
                        dumpNodes(w, fn.Body, depth+1)
                        }
                        dumpNode(w, val, depth+1)
                case Nodes:
-                       if val.Len() == 0 {
+                       if len(val) == 0 {
                                continue
                        }
                        if name != "" {
 }
 
 func dumpNodes(w io.Writer, list Nodes, depth int) {
-       if list.Len() == 0 {
+       if len(list) == 0 {
                fmt.Fprintf(w, " <nil>")
                return
        }
 
-       for _, n := range list.Slice() {
+       for _, n := range list {
                dumpNode(w, n, depth)
        }
 }
 
 // The methods that would modify it panic instead.
 var immutableEmptyNodes = Nodes{}
 
-// asNodes returns a slice of *Node as a Nodes value.
-func AsNodes(s []Node) Nodes {
-       return s
-}
-
-// Slice returns the entries in Nodes as a slice.
-// Changes to the slice entries (as in s[i] = n) will be reflected in
-// the Nodes.
-func (n Nodes) Slice() []Node {
-       return n
-}
-
-// Len returns the number of entries in Nodes.
-func (n Nodes) Len() int {
-       return len(n)
-}
-
-// Index returns the i'th element of Nodes.
-// It panics if n does not have at least i+1 elements.
-func (n Nodes) Index(i int) Node {
-       return n[i]
-}
-
-// First returns the first element of Nodes (same as n.Index(0)).
-// It panics if n has no elements.
-func (n Nodes) First() Node {
-       return n[0]
-}
-
-// Second returns the second element of Nodes (same as n.Index(1)).
-// It panics if n has fewer than two elements.
-func (n Nodes) Second() Node {
-       return n[1]
-}
-
 func (n *Nodes) mutate() {
        if n == &immutableEmptyNodes {
                panic("immutable Nodes.Set")
        *n = s
 }
 
-// Set1 sets n to a slice containing a single node.
-func (n *Nodes) Set1(n1 Node) {
-       n.mutate()
-       *n = []Node{n1}
-}
-
-// Set2 sets n to a slice containing two nodes.
-func (n *Nodes) Set2(n1, n2 Node) {
-       n.mutate()
-       *n = []Node{n1, n2}
-}
-
-// Set3 sets n to a slice containing three nodes.
-func (n *Nodes) Set3(n1, n2, n3 Node) {
-       n.mutate()
-       *n = []Node{n1, n2, n3}
-}
-
-// MoveNodes sets n to the contents of n2, then clears n2.
-func (n *Nodes) MoveNodes(n2 *Nodes) {
-       n.mutate()
-       *n = *n2
-       *n2 = nil
-}
-
-// SetIndex sets the i'th element of Nodes to node.
-// It panics if n does not have at least i+1 elements.
-func (n Nodes) SetIndex(i int, node Node) {
-       n[i] = node
-}
-
-// SetFirst sets the first element of Nodes to node.
-// It panics if n does not have at least one elements.
-func (n Nodes) SetFirst(node Node) {
-       n[0] = node
-}
-
-// SetSecond sets the second element of Nodes to node.
-// It panics if n does not have at least two elements.
-func (n Nodes) SetSecond(node Node) {
-       n[1] = node
-}
-
-// Addr returns the address of the i'th element of Nodes.
-// It panics if n does not have at least i+1 elements.
-func (n Nodes) Addr(i int) *Node {
-       return &n[i]
-}
-
 // Append appends entries to Nodes.
 func (n *Nodes) Append(a ...Node) {
        if len(a) == 0 {
        return ret
 }
 
-// AppendNodes appends the contents of *n2 to n, then clears n2.
-func (n *Nodes) AppendNodes(n2 *Nodes) {
-       n.mutate()
-       *n = append(*n, n2.Take()...)
-}
-
 // Copy returns a copy of the content of the slice.
 func (n Nodes) Copy() Nodes {
        if n == nil {
                return nil
        }
-       c := make(Nodes, n.Len())
+       c := make(Nodes, len(n))
        copy(c, n)
        return c
 }
 
 // Note that DoList only calls do on the nodes in the list, not their children.
 // If x's children should be processed, do(x) must call DoChildren(x, do) itself.
 func DoList(list Nodes, do func(Node) error) error {
-       for _, x := range list.Slice() {
+       for _, x := range list {
                if x != nil {
                        if err := do(x); err != nil {
                                return err
 
 // VisitList calls Visit(x, visit) for each node x in the list.
 func VisitList(list Nodes, visit func(Node)) {
-       for _, x := range list.Slice() {
+       for _, x := range list {
                Visit(x, visit)
        }
 }
 // Otherwise, AnyList returns false after calling Any(x, cond)
 // for every x in the list.
 func AnyList(list Nodes, cond func(Node) bool) bool {
-       for _, x := range list.Slice() {
+       for _, x := range list {
                if Any(x, cond) {
                        return true
                }
 // Note that editList only calls edit on the nodes in the list, not their children.
 // If x's children should be processed, edit(x) must call EditChildren(x, edit) itself.
 func editList(list Nodes, edit func(Node) Node) {
-       s := list.Slice()
-       for i, x := range list.Slice() {
+       s := list
+       for i, x := range list {
                if x != nil {
                        s[i] = edit(x)
                }