| // run -goexperiment rangefunc |
| |
| // Copyright 2023 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Test the 'for range' construct ranging over functions. |
| |
| package main |
| |
| var gj int |
| |
| func yield4x(yield func() bool) { |
| _ = yield() && yield() && yield() && yield() |
| } |
| |
| func yield4(yield func(int) bool) { |
| _ = yield(1) && yield(2) && yield(3) && yield(4) |
| } |
| |
| func yield3(yield func(int) bool) { |
| _ = yield(1) && yield(2) && yield(3) |
| } |
| |
| func yield2(yield func(int) bool) { |
| _ = yield(1) && yield(2) |
| } |
| |
| func testfunc0() { |
| j := 0 |
| for range yield4x { |
| j++ |
| } |
| if j != 4 { |
| println("wrong count ranging over yield4x:", j) |
| panic("testfunc0") |
| } |
| |
| j = 0 |
| for _ = range yield4 { |
| j++ |
| } |
| if j != 4 { |
| println("wrong count ranging over yield4:", j) |
| panic("testfunc0") |
| } |
| } |
| |
| func testfunc1() { |
| bad := false |
| j := 1 |
| for i := range yield4 { |
| if i != j { |
| println("range var", i, "want", j) |
| bad = true |
| } |
| j++ |
| } |
| if j != 5 { |
| println("wrong count ranging over f:", j) |
| bad = true |
| } |
| if bad { |
| panic("testfunc1") |
| } |
| } |
| |
| func testfunc2() { |
| bad := false |
| j := 1 |
| var i int |
| for i = range yield4 { |
| if i != j { |
| println("range var", i, "want", j) |
| bad = true |
| } |
| j++ |
| } |
| if j != 5 { |
| println("wrong count ranging over f:", j) |
| bad = true |
| } |
| if i != 4 { |
| println("wrong final i ranging over f:", i) |
| bad = true |
| } |
| if bad { |
| panic("testfunc2") |
| } |
| } |
| |
| func testfunc3() { |
| bad := false |
| j := 1 |
| var i int |
| for i = range yield4 { |
| if i != j { |
| println("range var", i, "want", j) |
| bad = true |
| } |
| j++ |
| if i == 2 { |
| break |
| } |
| continue |
| } |
| if j != 3 { |
| println("wrong count ranging over f:", j) |
| bad = true |
| } |
| if i != 2 { |
| println("wrong final i ranging over f:", i) |
| bad = true |
| } |
| if bad { |
| panic("testfunc3") |
| } |
| } |
| |
| func testfunc4() { |
| bad := false |
| j := 1 |
| var i int |
| func() { |
| for i = range yield4 { |
| if i != j { |
| println("range var", i, "want", j) |
| bad = true |
| } |
| j++ |
| if i == 2 { |
| return |
| } |
| } |
| }() |
| if j != 3 { |
| println("wrong count ranging over f:", j) |
| bad = true |
| } |
| if i != 2 { |
| println("wrong final i ranging over f:", i) |
| bad = true |
| } |
| if bad { |
| panic("testfunc3") |
| } |
| } |
| |
| func func5() (int, int) { |
| for i := range yield4 { |
| return 10, i |
| } |
| panic("still here") |
| } |
| |
| func testfunc5() { |
| x, y := func5() |
| if x != 10 || y != 1 { |
| println("wrong results", x, y, "want", 10, 1) |
| panic("testfunc5") |
| } |
| } |
| |
| func func6() (z, w int) { |
| for i := range yield4 { |
| z = 10 |
| w = i |
| return |
| } |
| panic("still here") |
| } |
| |
| func testfunc6() { |
| x, y := func6() |
| if x != 10 || y != 1 { |
| println("wrong results", x, y, "want", 10, 1) |
| panic("testfunc6") |
| } |
| } |
| |
| var saved []int |
| |
| func save(x int) { |
| saved = append(saved, x) |
| } |
| |
| func printslice(s []int) { |
| print("[") |
| for i, x := range s { |
| if i > 0 { |
| print(", ") |
| } |
| print(x) |
| } |
| print("]") |
| } |
| |
| func eqslice(s, t []int) bool { |
| if len(s) != len(t) { |
| return false |
| } |
| for i, x := range s { |
| if x != t[i] { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func func7() { |
| defer save(-1) |
| for i := range yield4 { |
| defer save(i) |
| } |
| defer save(5) |
| } |
| |
| func checkslice(name string, saved, want []int) { |
| if !eqslice(saved, want) { |
| print("wrong results ") |
| printslice(saved) |
| print(" want ") |
| printslice(want) |
| print("\n") |
| panic(name) |
| } |
| } |
| |
| func testfunc7() { |
| saved = nil |
| func7() |
| want := []int{5, 4, 3, 2, 1, -1} |
| checkslice("testfunc7", saved, want) |
| } |
| |
| func func8() { |
| defer save(-1) |
| for i := range yield2 { |
| for j := range yield3 { |
| defer save(i*10 + j) |
| } |
| defer save(i) |
| } |
| defer save(-2) |
| for i := range yield4 { |
| defer save(i) |
| } |
| defer save(-3) |
| } |
| |
| func testfunc8() { |
| saved = nil |
| func8() |
| want := []int{-3, 4, 3, 2, 1, -2, 2, 23, 22, 21, 1, 13, 12, 11, -1} |
| checkslice("testfunc8", saved, want) |
| } |
| |
| func func9() { |
| n := 0 |
| for _ = range yield2 { |
| for _ = range yield3 { |
| n++ |
| defer save(n) |
| } |
| } |
| } |
| |
| func testfunc9() { |
| saved = nil |
| func9() |
| want := []int{6, 5, 4, 3, 2, 1} |
| checkslice("testfunc9", saved, want) |
| } |
| |
| // test that range evaluates the index and value expressions |
| // exactly once per iteration. |
| |
| var ncalls = 0 |
| |
| func getvar(p *int) *int { |
| ncalls++ |
| return p |
| } |
| |
| func iter2(list ...int) func(func(int, int) bool) { |
| return func(yield func(int, int) bool) { |
| for i, x := range list { |
| if !yield(i, x) { |
| return |
| } |
| } |
| } |
| } |
| |
| func testcalls() { |
| var i, v int |
| ncalls = 0 |
| si := 0 |
| sv := 0 |
| for *getvar(&i), *getvar(&v) = range iter2(1, 2) { |
| si += i |
| sv += v |
| } |
| if ncalls != 4 { |
| println("wrong number of calls:", ncalls, "!= 4") |
| panic("fail") |
| } |
| if si != 1 || sv != 3 { |
| println("wrong sum in testcalls", si, sv) |
| panic("fail") |
| } |
| } |
| |
| type iter3YieldFunc func(int, int) bool |
| |
| func iter3(list ...int) func(iter3YieldFunc) { |
| return func(yield iter3YieldFunc) { |
| for k, v := range list { |
| if !yield(k, v) { |
| return |
| } |
| } |
| } |
| } |
| |
| func testcalls1() { |
| ncalls := 0 |
| for k, v := range iter3(1, 2, 3) { |
| _, _ = k, v |
| ncalls++ |
| } |
| if ncalls != 3 { |
| println("wrong number of calls:", ncalls, "!= 3") |
| panic("fail") |
| } |
| } |
| |
| func main() { |
| testfunc0() |
| testfunc1() |
| testfunc2() |
| testfunc3() |
| testfunc4() |
| testfunc5() |
| testfunc6() |
| testfunc7() |
| testfunc8() |
| testfunc9() |
| testcalls() |
| testcalls1() |
| } |