mirror of
https://github.com/golang/go
synced 2024-09-28 18:14:29 -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:
parent
40818038bf
commit
27b248b307
@ -347,21 +347,19 @@ func (e *escape) stmt(n ir.Node) {
|
|||||||
e.loopDepth--
|
e.loopDepth--
|
||||||
|
|
||||||
case ir.ORANGE:
|
case ir.ORANGE:
|
||||||
// for List = range Right { Nbody }
|
// for Key, Value = range X { Body }
|
||||||
n := n.(*ir.RangeStmt)
|
n := n.(*ir.RangeStmt)
|
||||||
e.loopDepth++
|
e.loopDepth++
|
||||||
ks := e.addrs(n.Vars)
|
e.addr(n.Key)
|
||||||
|
k := e.addr(n.Value)
|
||||||
e.block(n.Body)
|
e.block(n.Body)
|
||||||
e.loopDepth--
|
e.loopDepth--
|
||||||
|
|
||||||
// Right is evaluated outside the loop.
|
// X is evaluated outside the loop.
|
||||||
k := e.discardHole()
|
|
||||||
if len(ks) >= 2 {
|
|
||||||
if n.X.Type().IsArray() {
|
if n.X.Type().IsArray() {
|
||||||
k = ks[1].note(n, "range")
|
k = k.note(n, "range")
|
||||||
} else {
|
} else {
|
||||||
k = ks[1].deref(n, "range-deref")
|
k = k.deref(n, "range-deref")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
e.expr(e.later(k), n.X)
|
e.expr(e.later(k), n.X)
|
||||||
|
|
||||||
|
@ -444,12 +444,15 @@ func stmtFmt(n Node, s fmt.State) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(n.Vars) == 0 {
|
fmt.Fprint(s, "for")
|
||||||
fmt.Fprintf(s, "for range %v { %v }", n.X, n.Body)
|
if n.Key != nil {
|
||||||
break
|
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:
|
case OSELECT:
|
||||||
n := n.(*SelectStmt)
|
n := n.(*SelectStmt)
|
||||||
|
@ -724,22 +724,23 @@ func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
|||||||
func (n *RangeStmt) copy() Node {
|
func (n *RangeStmt) copy() Node {
|
||||||
c := *n
|
c := *n
|
||||||
c.init = c.init.Copy()
|
c.init = c.init.Copy()
|
||||||
c.Vars = c.Vars.Copy()
|
|
||||||
c.Body = c.Body.Copy()
|
c.Body = c.Body.Copy()
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
func (n *RangeStmt) doChildren(do func(Node) error) error {
|
func (n *RangeStmt) doChildren(do func(Node) error) error {
|
||||||
var err error
|
var err error
|
||||||
err = maybeDoList(n.init, err, do)
|
err = maybeDoList(n.init, err, do)
|
||||||
err = maybeDoList(n.Vars, err, do)
|
|
||||||
err = maybeDo(n.X, 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)
|
err = maybeDoList(n.Body, err, do)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
func (n *RangeStmt) editChildren(edit func(Node) Node) {
|
func (n *RangeStmt) editChildren(edit func(Node) Node) {
|
||||||
editList(n.init, edit)
|
editList(n.init, edit)
|
||||||
editList(n.Vars, edit)
|
|
||||||
n.X = maybeEdit(n.X, edit)
|
n.X = maybeEdit(n.X, edit)
|
||||||
|
n.Key = maybeEdit(n.Key, edit)
|
||||||
|
n.Value = maybeEdit(n.Value, edit)
|
||||||
editList(n.Body, edit)
|
editList(n.Body, edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,25 +290,24 @@ func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
|
|||||||
|
|
||||||
func (n *LabelStmt) Sym() *types.Sym { return n.Label }
|
func (n *LabelStmt) Sym() *types.Sym { return n.Label }
|
||||||
|
|
||||||
// A RangeStmt is a range loop: for Vars = range X { Stmts }
|
// A RangeStmt is a range loop: for Key, Value = range X { Body }
|
||||||
// Op can be OFOR or OFORUNTIL (!Cond).
|
|
||||||
type RangeStmt struct {
|
type RangeStmt struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
Label *types.Sym
|
Label *types.Sym
|
||||||
Vars Nodes // TODO(rsc): Replace with Key, Value Node
|
|
||||||
Def bool
|
Def bool
|
||||||
X Node
|
X Node
|
||||||
|
Key Node
|
||||||
|
Value Node
|
||||||
Body Nodes
|
Body Nodes
|
||||||
HasBreak bool
|
HasBreak bool
|
||||||
typ *types.Type // TODO(rsc): Remove - use X.Type() instead
|
typ *types.Type // TODO(rsc): Remove - use X.Type() instead
|
||||||
Prealloc *Name
|
Prealloc *Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt {
|
func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt {
|
||||||
n := &RangeStmt{X: x}
|
n := &RangeStmt{X: x, Key: key, Value: value}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = ORANGE
|
n.op = ORANGE
|
||||||
n.Vars.Set(vars)
|
|
||||||
n.Body.Set(body)
|
n.Body.Set(body)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
@ -1172,10 +1172,14 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node {
|
|||||||
panic("unexpected RangeClause")
|
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 {
|
if r.Lhs != nil {
|
||||||
n.Def = r.Def
|
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))
|
n.Body.Set(p.blockStmt(stmt.Body))
|
||||||
p.closeAnotherScope()
|
p.closeAnotherScope()
|
||||||
|
@ -1143,7 +1143,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
|||||||
n := n.(*ir.RangeStmt)
|
n := n.(*ir.RangeStmt)
|
||||||
w.op(ir.ORANGE)
|
w.op(ir.ORANGE)
|
||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
w.stmtList(n.Vars)
|
w.exprsOrNil(n.Key, n.Value)
|
||||||
w.expr(n.X)
|
w.expr(n.X)
|
||||||
w.stmtList(n.Body)
|
w.stmtList(n.Body)
|
||||||
|
|
||||||
|
@ -1028,7 +1028,9 @@ func (r *importReader) node() ir.Node {
|
|||||||
return ir.NewForStmt(pos, init, cond, post, r.stmtList())
|
return ir.NewForStmt(pos, init, cond, post, r.stmtList())
|
||||||
|
|
||||||
case ir.ORANGE:
|
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:
|
case ir.OSELECT:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
|
@ -19,19 +19,18 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// delicate little dance. see typecheckas2
|
// delicate little dance. see typecheckas2
|
||||||
ls := n.Vars
|
if n.Key != nil && !ir.DeclaredBy(n.Key, n) {
|
||||||
for i1, n1 := range ls {
|
n.Key = AssignExpr(n.Key)
|
||||||
if !ir.DeclaredBy(n1, n) {
|
|
||||||
ls[i1] = AssignExpr(ls[i1])
|
|
||||||
}
|
}
|
||||||
|
if n.Value != nil && !ir.DeclaredBy(n.Value, n) {
|
||||||
|
n.Value = AssignExpr(n.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.IsPtr() && t.Elem().IsArray() {
|
if t.IsPtr() && t.Elem().IsArray() {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
|
|
||||||
var t1, t2 *types.Type
|
var tk, tv *types.Type
|
||||||
toomany := false
|
toomany := false
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
default:
|
default:
|
||||||
@ -39,12 +38,12 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
case types.TARRAY, types.TSLICE:
|
case types.TARRAY, types.TSLICE:
|
||||||
t1 = types.Types[types.TINT]
|
tk = types.Types[types.TINT]
|
||||||
t2 = t.Elem()
|
tv = t.Elem()
|
||||||
|
|
||||||
case types.TMAP:
|
case types.TMAP:
|
||||||
t1 = t.Key()
|
tk = t.Key()
|
||||||
t2 = t.Elem()
|
tv = t.Elem()
|
||||||
|
|
||||||
case types.TCHAN:
|
case types.TCHAN:
|
||||||
if !t.ChanDir().CanRecv() {
|
if !t.ChanDir().CanRecv() {
|
||||||
@ -52,61 +51,35 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t1 = t.Elem()
|
tk = t.Elem()
|
||||||
t2 = nil
|
tv = nil
|
||||||
if len(n.Vars) == 2 {
|
if n.Value != nil {
|
||||||
toomany = true
|
toomany = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.TSTRING:
|
case types.TSTRING:
|
||||||
t1 = types.Types[types.TINT]
|
tk = types.Types[types.TINT]
|
||||||
t2 = types.RuneType
|
tv = types.RuneType
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(n.Vars) > 2 || toomany {
|
if toomany {
|
||||||
base.ErrorfAt(n.Pos(), "too many variables in range")
|
base.ErrorfAt(n.Pos(), "too many variables in range")
|
||||||
}
|
}
|
||||||
|
|
||||||
var v1, v2 ir.Node
|
do := func(nn ir.Node, t *types.Type) {
|
||||||
if len(n.Vars) != 0 {
|
if nn != nil {
|
||||||
v1 = n.Vars[0]
|
if ir.DeclaredBy(nn, n) {
|
||||||
}
|
nn.SetType(t)
|
||||||
if len(n.Vars) > 1 {
|
} else if nn.Type() != nil {
|
||||||
v2 = n.Vars[1]
|
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)
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkassign(n, v1)
|
checkassign(n, nn)
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
// type check assignment.
|
||||||
@ -399,11 +372,11 @@ func tcRange(n *ir.RangeStmt) {
|
|||||||
|
|
||||||
// second half of dance, the first half being typecheckrangeExpr
|
// second half of dance, the first half being typecheckrangeExpr
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
ls := n.Vars
|
if n.Key != nil && n.Key.Typecheck() == 0 {
|
||||||
for i1, n1 := range ls {
|
n.Key = AssignExpr(n.Key)
|
||||||
if n1.Typecheck() == 0 {
|
|
||||||
ls[i1] = AssignExpr(ls[i1])
|
|
||||||
}
|
}
|
||||||
|
if n.Value != nil && n.Value.Typecheck() == 0 {
|
||||||
|
n.Value = AssignExpr(n.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
decldepth++
|
decldepth++
|
||||||
|
@ -848,7 +848,7 @@ func (o *orderState) stmt(n ir.Node) {
|
|||||||
base.Fatalf("order.stmt range %v", n.Type())
|
base.Fatalf("order.stmt range %v", n.Type())
|
||||||
|
|
||||||
case types.TARRAY, types.TSLICE:
|
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).
|
// for i := range x will only use x once, to compute len(x).
|
||||||
// No need to copy it.
|
// No need to copy it.
|
||||||
break
|
break
|
||||||
@ -887,7 +887,8 @@ func (o *orderState) stmt(n ir.Node) {
|
|||||||
// hiter contains pointers and needs to be zeroed.
|
// hiter contains pointers and needs to be zeroed.
|
||||||
n.Prealloc = o.newTemp(reflectdata.MapIterType(n.Type()), true)
|
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 {
|
if orderBody {
|
||||||
orderBlock(&n.Body, o.free)
|
orderBlock(&n.Body, o.free)
|
||||||
}
|
}
|
||||||
|
@ -61,15 +61,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
|||||||
a := nrange.X
|
a := nrange.X
|
||||||
lno := ir.SetPos(a)
|
lno := ir.SetPos(a)
|
||||||
|
|
||||||
var v1, v2 ir.Node
|
v1, v2 := nrange.Key, nrange.Value
|
||||||
l := len(nrange.Vars)
|
|
||||||
if l > 0 {
|
|
||||||
v1 = nrange.Vars[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if l > 1 {
|
|
||||||
v2 = nrange.Vars[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if ir.IsBlank(v2) {
|
if ir.IsBlank(v2) {
|
||||||
v2 = nil
|
v2 = nil
|
||||||
@ -343,15 +335,11 @@ func isMapClear(n *ir.RangeStmt) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || len(n.Vars) != 1 {
|
if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || n.Key == nil || n.Value != nil {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
k := n.Vars[0]
|
|
||||||
if k == nil || ir.IsBlank(k) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k := n.Key
|
||||||
// Require k to be a new variable name.
|
// Require k to be a new variable name.
|
||||||
if !ir.DeclaredBy(k, n) {
|
if !ir.DeclaredBy(k, n) {
|
||||||
return false
|
return false
|
||||||
|
Loading…
Reference in New Issue
Block a user