aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/walk/range.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/walk/range.go')
-rw-r--r--src/cmd/compile/internal/walk/range.go69
1 files changed, 46 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/walk/range.go b/src/cmd/compile/internal/walk/range.go
index 6c30fa2877..b697c243c7 100644
--- a/src/cmd/compile/internal/walk/range.go
+++ b/src/cmd/compile/internal/walk/range.go
@@ -38,11 +38,7 @@ func cheapComputableIndex(width int64) bool {
// the returned node.
func walkRange(nrange *ir.RangeStmt) ir.Node {
if isMapClear(nrange) {
- m := nrange.X
- lno := ir.SetPos(m)
- n := mapClear(m)
- base.Pos = lno
- return n
+ return mapClear(nrange)
}
nfor := ir.NewForStmt(nrange.Pos(), nil, nil, nil, nil)
@@ -107,7 +103,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
// for v1 := range ha { body }
if v2 == nil {
- body = []ir.Node{ir.NewAssignStmt(base.Pos, v1, hv1)}
+ body = []ir.Node{rangeAssign(nrange, hv1)}
break
}
@@ -116,10 +112,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
// v1, v2 = hv1, ha[hv1]
tmp := ir.NewIndexExpr(base.Pos, ha, hv1)
tmp.SetBounded(true)
- // Use OAS2 to correctly handle assignments
- // of the form "v1, a[v1] := range".
- a := ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{v1, v2}, []ir.Node{hv1, tmp})
- body = []ir.Node{a}
+ body = []ir.Node{rangeAssign2(nrange, hv1, tmp)}
break
}
@@ -144,9 +137,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
tmp.SetBounded(true)
init = append(init, ir.NewAssignStmt(base.Pos, hp, typecheck.NodAddr(tmp)))
- // Use OAS2 to correctly handle assignments
- // of the form "v1, a[v1] := range".
- a := ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{v1, v2}, []ir.Node{hv1, ir.NewStarExpr(base.Pos, hp)})
+ a := rangeAssign2(nrange, hv1, ir.NewStarExpr(base.Pos, hp))
body = append(body, a)
// Advance pointer as part of the late increment.
@@ -172,7 +163,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
fn := typecheck.LookupRuntime("mapiterinit")
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), th)
- init = append(init, mkcallstmt1(fn, reflectdata.TypePtr(t), ha, typecheck.NodAddr(hit)))
+ init = append(init, mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), ha, typecheck.NodAddr(hit)))
nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil())
fn = typecheck.LookupRuntime("mapiternext")
@@ -183,11 +174,10 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
if v1 == nil {
body = nil
} else if v2 == nil {
- body = []ir.Node{ir.NewAssignStmt(base.Pos, v1, key)}
+ body = []ir.Node{rangeAssign(nrange, key)}
} else {
elem := ir.NewStarExpr(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, elemsym))
- a := ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{v1, v2}, []ir.Node{key, elem})
- body = []ir.Node{a}
+ body = []ir.Node{rangeAssign2(nrange, key, elem)}
}
case types.TCHAN:
@@ -210,7 +200,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
if v1 == nil {
body = nil
} else {
- body = []ir.Node{ir.NewAssignStmt(base.Pos, v1, hv1)}
+ body = []ir.Node{rangeAssign(nrange, hv1)}
}
// Zero hv1. This prevents hv1 from being the sole, inaccessible
// reference to an otherwise GC-able value during the next channel receive.
@@ -275,11 +265,10 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
if v1 != nil {
if v2 != nil {
// v1, v2 = hv1t, hv2
- a := ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{v1, v2}, []ir.Node{hv1t, hv2})
- body = append(body, a)
+ body = append(body, rangeAssign2(nrange, hv1t, hv2))
} else {
// v1 = hv1t
- body = append(body, ir.NewAssignStmt(base.Pos, v1, hv1t))
+ body = append(body, rangeAssign(nrange, hv1t))
}
}
}
@@ -314,6 +303,36 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
return n
}
+// rangeAssign returns "n.Key = key".
+func rangeAssign(n *ir.RangeStmt, key ir.Node) ir.Node {
+ key = rangeConvert(n, n.Key.Type(), key, n.KeyTypeWord, n.KeySrcRType)
+ return ir.NewAssignStmt(n.Pos(), n.Key, key)
+}
+
+// rangeAssign2 returns "n.Key, n.Value = key, value".
+func rangeAssign2(n *ir.RangeStmt, key, value ir.Node) ir.Node {
+ // Use OAS2 to correctly handle assignments
+ // of the form "v1, a[v1] = range".
+ key = rangeConvert(n, n.Key.Type(), key, n.KeyTypeWord, n.KeySrcRType)
+ value = rangeConvert(n, n.Value.Type(), value, n.ValueTypeWord, n.ValueSrcRType)
+ return ir.NewAssignListStmt(n.Pos(), ir.OAS2, []ir.Node{n.Key, n.Value}, []ir.Node{key, value})
+}
+
+// rangeConvert returns src, converted to dst if necessary. If a
+// conversion is necessary, then typeWord and srcRType are copied to
+// their respective ConvExpr fields.
+func rangeConvert(nrange *ir.RangeStmt, dst *types.Type, src, typeWord, srcRType ir.Node) ir.Node {
+ src = typecheck.Expr(src)
+ if dst.Kind() == types.TBLANK || types.Identical(dst, src.Type()) {
+ return src
+ }
+
+ n := ir.NewConvExpr(nrange.Pos(), ir.OCONV, dst, src)
+ n.TypeWord = typeWord
+ n.SrcRType = srcRType
+ return typecheck.Expr(n)
+}
+
// isMapClear checks if n is of the form:
//
// for k := range m {
@@ -360,13 +379,17 @@ func isMapClear(n *ir.RangeStmt) bool {
}
// mapClear constructs a call to runtime.mapclear for the map m.
-func mapClear(m ir.Node) ir.Node {
+func mapClear(nrange *ir.RangeStmt) ir.Node {
+ m := nrange.X
+ origPos := ir.SetPos(m)
+ defer func() { base.Pos = origPos }()
+
t := m.Type()
// instantiate mapclear(typ *type, hmap map[any]any)
fn := typecheck.LookupRuntime("mapclear")
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
- n := mkcallstmt1(fn, reflectdata.TypePtr(t), m)
+ n := mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), m)
return walkStmt(typecheck.Stmt(n))
}