1
0
mirror of https://github.com/golang/go synced 2024-09-23 11:10:12 -06:00

[dev.regabi] cmd/compile: separate range stmt Vars to Key, Value nodes

Passes buildall w/ toolstash -cmp.

Change-Id: I9738fcabc8ebf3afa34d102afadf1b474b50db35
Reviewed-on: https://go-review.googlesource.com/c/go/+/279435
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Cuong Manh Le 2020-12-24 13:09:20 +07:00
parent 40818038bf
commit 27b248b307
10 changed files with 73 additions and 104 deletions

View File

@ -347,21 +347,19 @@ func (e *escape) stmt(n ir.Node) {
e.loopDepth--
case ir.ORANGE:
// for List = range Right { Nbody }
// for Key, Value = range X { Body }
n := n.(*ir.RangeStmt)
e.loopDepth++
ks := e.addrs(n.Vars)
e.addr(n.Key)
k := e.addr(n.Value)
e.block(n.Body)
e.loopDepth--
// Right is evaluated outside the loop.
k := e.discardHole()
if len(ks) >= 2 {
if n.X.Type().IsArray() {
k = ks[1].note(n, "range")
} else {
k = ks[1].deref(n, "range-deref")
}
// X is evaluated outside the loop.
if n.X.Type().IsArray() {
k = k.note(n, "range")
} else {
k = k.deref(n, "range-deref")
}
e.expr(e.later(k), n.X)

View File

@ -444,12 +444,15 @@ func stmtFmt(n Node, s fmt.State) {
break
}
if len(n.Vars) == 0 {
fmt.Fprintf(s, "for range %v { %v }", n.X, n.Body)
break
fmt.Fprint(s, "for")
if n.Key != nil {
fmt.Fprintf(s, " %v", n.Key)
if n.Value != nil {
fmt.Fprintf(s, ", %v", n.Value)
}
fmt.Fprint(s, " =")
}
fmt.Fprintf(s, "for %.v = range %v { %v }", n.Vars, n.X, n.Body)
fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)
case OSELECT:
n := n.(*SelectStmt)

View File

@ -724,22 +724,23 @@ func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *RangeStmt) copy() Node {
c := *n
c.init = c.init.Copy()
c.Vars = c.Vars.Copy()
c.Body = c.Body.Copy()
return &c
}
func (n *RangeStmt) doChildren(do func(Node) error) error {
var err error
err = maybeDoList(n.init, err, do)
err = maybeDoList(n.Vars, err, do)
err = maybeDo(n.X, err, do)
err = maybeDo(n.Key, err, do)
err = maybeDo(n.Value, err, do)
err = maybeDoList(n.Body, err, do)
return err
}
func (n *RangeStmt) editChildren(edit func(Node) Node) {
editList(n.init, edit)
editList(n.Vars, edit)
n.X = maybeEdit(n.X, edit)
n.Key = maybeEdit(n.Key, edit)
n.Value = maybeEdit(n.Value, edit)
editList(n.Body, edit)
}

View File

@ -290,25 +290,24 @@ func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
func (n *LabelStmt) Sym() *types.Sym { return n.Label }
// A RangeStmt is a range loop: for Vars = range X { Stmts }
// Op can be OFOR or OFORUNTIL (!Cond).
// A RangeStmt is a range loop: for Key, Value = range X { Body }
type RangeStmt struct {
miniStmt
Label *types.Sym
Vars Nodes // TODO(rsc): Replace with Key, Value Node
Def bool
X Node
Key Node
Value Node
Body Nodes
HasBreak bool
typ *types.Type // TODO(rsc): Remove - use X.Type() instead
Prealloc *Name
}
func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt {
n := &RangeStmt{X: x}
func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt {
n := &RangeStmt{X: x, Key: key, Value: value}
n.pos = pos
n.op = ORANGE
n.Vars.Set(vars)
n.Body.Set(body)
return n
}

View File

@ -1172,10 +1172,14 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node {
panic("unexpected RangeClause")
}
n := ir.NewRangeStmt(p.pos(r), nil, p.expr(r.X), nil)
n := ir.NewRangeStmt(p.pos(r), nil, nil, p.expr(r.X), nil)
if r.Lhs != nil {
n.Def = r.Def
n.Vars.Set(p.assignList(r.Lhs, n, n.Def))
lhs := p.assignList(r.Lhs, n, n.Def)
n.Key = lhs[0]
if len(lhs) > 1 {
n.Value = lhs[1]
}
}
n.Body.Set(p.blockStmt(stmt.Body))
p.closeAnotherScope()

View File

@ -1143,7 +1143,7 @@ func (w *exportWriter) stmt(n ir.Node) {
n := n.(*ir.RangeStmt)
w.op(ir.ORANGE)
w.pos(n.Pos())
w.stmtList(n.Vars)
w.exprsOrNil(n.Key, n.Value)
w.expr(n.X)
w.stmtList(n.Body)

View File

@ -1028,7 +1028,9 @@ func (r *importReader) node() ir.Node {
return ir.NewForStmt(pos, init, cond, post, r.stmtList())
case ir.ORANGE:
return ir.NewRangeStmt(r.pos(), r.stmtList(), r.expr(), r.stmtList())
pos := r.pos()
k, v := r.exprsOrNil()
return ir.NewRangeStmt(pos, k, v, r.expr(), r.stmtList())
case ir.OSELECT:
pos := r.pos()

View File

@ -19,19 +19,18 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
return
}
// delicate little dance. see typecheckas2
ls := n.Vars
for i1, n1 := range ls {
if !ir.DeclaredBy(n1, n) {
ls[i1] = AssignExpr(ls[i1])
}
if n.Key != nil && !ir.DeclaredBy(n.Key, n) {
n.Key = AssignExpr(n.Key)
}
if n.Value != nil && !ir.DeclaredBy(n.Value, n) {
n.Value = AssignExpr(n.Value)
}
if t.IsPtr() && t.Elem().IsArray() {
t = t.Elem()
}
n.SetType(t)
var t1, t2 *types.Type
var tk, tv *types.Type
toomany := false
switch t.Kind() {
default:
@ -39,12 +38,12 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
return
case types.TARRAY, types.TSLICE:
t1 = types.Types[types.TINT]
t2 = t.Elem()
tk = types.Types[types.TINT]
tv = t.Elem()
case types.TMAP:
t1 = t.Key()
t2 = t.Elem()
tk = t.Key()
tv = t.Elem()
case types.TCHAN:
if !t.ChanDir().CanRecv() {
@ -52,61 +51,35 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
return
}
t1 = t.Elem()
t2 = nil
if len(n.Vars) == 2 {
tk = t.Elem()
tv = nil
if n.Value != nil {
toomany = true
}
case types.TSTRING:
t1 = types.Types[types.TINT]
t2 = types.RuneType
tk = types.Types[types.TINT]
tv = types.RuneType
}
if len(n.Vars) > 2 || toomany {
if toomany {
base.ErrorfAt(n.Pos(), "too many variables in range")
}
var v1, v2 ir.Node
if len(n.Vars) != 0 {
v1 = n.Vars[0]
}
if len(n.Vars) > 1 {
v2 = n.Vars[1]
}
// this is not only an optimization but also a requirement in the spec.
// "if the second iteration variable is the blank identifier, the range
// clause is equivalent to the same clause with only the first variable
// present."
if ir.IsBlank(v2) {
if v1 != nil {
n.Vars = []ir.Node{v1}
}
v2 = nil
}
if v1 != nil {
if ir.DeclaredBy(v1, n) {
v1.SetType(t1)
} else if v1.Type() != nil {
if op, why := assignop(t1, v1.Type()); op == ir.OXXX {
base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t1, v1, why)
do := func(nn ir.Node, t *types.Type) {
if nn != nil {
if ir.DeclaredBy(nn, n) {
nn.SetType(t)
} else if nn.Type() != nil {
if op, why := assignop(t, nn.Type()); op == ir.OXXX {
base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t, nn, why)
}
}
checkassign(n, nn)
}
checkassign(n, v1)
}
if v2 != nil {
if ir.DeclaredBy(v2, n) {
v2.SetType(t2)
} else if v2.Type() != nil {
if op, why := assignop(t2, v2.Type()); op == ir.OXXX {
base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t2, v2, why)
}
}
checkassign(n, v2)
}
do(n.Key, tk)
do(n.Value, tv)
}
// type check assignment.
@ -399,11 +372,11 @@ func tcRange(n *ir.RangeStmt) {
// second half of dance, the first half being typecheckrangeExpr
n.SetTypecheck(1)
ls := n.Vars
for i1, n1 := range ls {
if n1.Typecheck() == 0 {
ls[i1] = AssignExpr(ls[i1])
}
if n.Key != nil && n.Key.Typecheck() == 0 {
n.Key = AssignExpr(n.Key)
}
if n.Value != nil && n.Value.Typecheck() == 0 {
n.Value = AssignExpr(n.Value)
}
decldepth++

View File

@ -848,7 +848,7 @@ func (o *orderState) stmt(n ir.Node) {
base.Fatalf("order.stmt range %v", n.Type())
case types.TARRAY, types.TSLICE:
if len(n.Vars) < 2 || ir.IsBlank(n.Vars[1]) {
if n.Value == nil || ir.IsBlank(n.Value) {
// for i := range x will only use x once, to compute len(x).
// No need to copy it.
break
@ -887,7 +887,8 @@ func (o *orderState) stmt(n ir.Node) {
// hiter contains pointers and needs to be zeroed.
n.Prealloc = o.newTemp(reflectdata.MapIterType(n.Type()), true)
}
o.exprListInPlace(n.Vars)
n.Key = o.exprInPlace(n.Key)
n.Value = o.exprInPlace(n.Value)
if orderBody {
orderBlock(&n.Body, o.free)
}

View File

@ -61,15 +61,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
a := nrange.X
lno := ir.SetPos(a)
var v1, v2 ir.Node
l := len(nrange.Vars)
if l > 0 {
v1 = nrange.Vars[0]
}
if l > 1 {
v2 = nrange.Vars[1]
}
v1, v2 := nrange.Key, nrange.Value
if ir.IsBlank(v2) {
v2 = nil
@ -343,15 +335,11 @@ func isMapClear(n *ir.RangeStmt) bool {
return false
}
if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || len(n.Vars) != 1 {
return false
}
k := n.Vars[0]
if k == nil || ir.IsBlank(k) {
if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || n.Key == nil || n.Value != nil {
return false
}
k := n.Key
// Require k to be a new variable name.
if !ir.DeclaredBy(k, n) {
return false