diff --git a/.travis.yml b/.travis.yml index c9048ec9..e3c84390 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,6 @@ cache: matrix: fast_finish: true include: - - go: 1.11.x - go: 1.12.x - go: 1.13.x env: STABLE=true diff --git a/_test/range3.go b/_test/range3.go new file mode 100644 index 00000000..ac127b0c --- /dev/null +++ b/_test/range3.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + m := map[int]bool{1: true, 3: true, 5: true} + for k := range m { + m[k*2] = true + } + fmt.Println("ok") +} + +// Output: +// ok diff --git a/_test/range4.go b/_test/range4.go new file mode 100644 index 00000000..7fe584c3 --- /dev/null +++ b/_test/range4.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + m := map[int]bool{1: true, 3: true, 5: true} + for _, v := range m { + fmt.Println(v) + } +} + +// Output: +// true +// true +// true diff --git a/_test/range5.go b/_test/range5.go new file mode 100644 index 00000000..6d248f94 --- /dev/null +++ b/_test/range5.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + m := map[int]bool{1: true, 3: true, 5: true} + var n int + for range m { + n++ + } + fmt.Println(n) +} + +// Output: +// 3 diff --git a/_test/range6.go b/_test/range6.go new file mode 100644 index 00000000..dc7e4faf --- /dev/null +++ b/_test/range6.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + "math" +) + +func main() { + m := map[float64]bool{math.NaN(): true, math.NaN(): true, math.NaN(): true} + for _, v := range m { + fmt.Println(v) + } +} + +// Output: +// true +// true +// true diff --git a/interp/cfg.go b/interp/cfg.go index d237932b..c1410f8e 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -87,6 +87,8 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { } case mapT: n.anc.gen = rangeMap + ityp := &itype{cat: valueT, rtype: reflect.TypeOf((*reflect.MapIter)(nil))} + sc.add(ityp) ktyp = o.typ.key vtyp = o.typ.val case ptrT: diff --git a/interp/run.go b/interp/run.go index 1bb8e0c8..b36fa577 100644 --- a/interp/run.go +++ b/interp/run.go @@ -1601,31 +1601,40 @@ func rangeChan(n *node) { } func rangeMap(n *node) { - index0 := n.child[0].findex // array index location in frame - index1 := n.child[1].findex // array value location in frame - value := genValue(n.child[2]) // array + index0 := n.child[0].findex // map index location in frame + index2 := index0 - 1 // iterator for range, always just behind index0 fnext := getExec(n.fnext) tnext := getExec(n.tnext) - // TODO: move i and keys to frame - var i int - var keys []reflect.Value - n.exec = func(f *frame) bltn { - a := value(f) - i++ - if i >= a.Len() { - return fnext + var value func(*frame) reflect.Value + if len(n.child) == 4 { + index1 := n.child[1].findex // map value location in frame + value = genValue(n.child[2]) // map + n.exec = func(f *frame) bltn { + iter := f.data[index2].Interface().(*reflect.MapIter) + if !iter.Next() { + return fnext + } + f.data[index0].Set(iter.Key()) + f.data[index1].Set(iter.Value()) + return tnext + } + } else { + value = genValue(n.child[1]) // map + n.exec = func(f *frame) bltn { + iter := f.data[index2].Interface().(*reflect.MapIter) + if !iter.Next() { + return fnext + } + f.data[index0].Set(iter.Key()) + return tnext } - f.data[index0].Set(keys[i]) - f.data[index1].Set(a.MapIndex(keys[i])) - return tnext } // Init sequence next := n.exec n.child[0].exec = func(f *frame) bltn { - keys = value(f).MapKeys() - i = -1 + f.data[index2].Set(reflect.ValueOf(value(f).MapRange())) return next } }