
TestRangeOverFuncNext and TestRangeOverFuncNextInlined are failing on linux/386 with go1.23 due to an inconsistency on how append works on 32bit platforms.
324 lines
6.4 KiB
Go
324 lines
6.4 KiB
Go
package main
|
|
|
|
// The tests here are adapted from $GOROOT/src/cmd/compile/internal/rangefunc/rangefunc_test.go
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
/*
|
|
|
|
|
|
|
|
THESE
|
|
LINES
|
|
INTENTIONALLY
|
|
LEFT
|
|
BLANK
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
func TestTrickyIterAll() {
|
|
trickItAll := TrickyIterator{}
|
|
i := 0
|
|
for _, x := range trickItAll.iterAll([]int{30, 7, 8, 9, 10}) {
|
|
i += x
|
|
if i >= 36 {
|
|
break
|
|
}
|
|
}
|
|
|
|
fmt.Println("Got i = ", i)
|
|
}
|
|
|
|
func TestTrickyIterAll2() {
|
|
trickItAll := TrickyIterator{}
|
|
i := 0
|
|
for _, x := range trickItAll.iterAll([]int{42, 47}) {
|
|
i += x
|
|
}
|
|
fmt.Println(i)
|
|
}
|
|
|
|
func TestBreak1() {
|
|
var result []int
|
|
for _, x := range OfSliceIndex([]int{-1, -2, -4}) {
|
|
if x == -4 {
|
|
break
|
|
}
|
|
for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
|
|
if y == 3 {
|
|
break
|
|
}
|
|
result = append(result, y)
|
|
}
|
|
result = append(result, x)
|
|
}
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func TestBreak2() {
|
|
var result []int
|
|
outer:
|
|
for _, x := range OfSliceIndex([]int{-1, -2, -4}) {
|
|
for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
|
|
if y == 3 {
|
|
break
|
|
}
|
|
if x == -4 {
|
|
break outer
|
|
}
|
|
result = append(result, y)
|
|
}
|
|
result = append(result, x)
|
|
}
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func TestMultiCont0() {
|
|
var result []int = make([]int, 0, 10)
|
|
|
|
W:
|
|
for _, w := range OfSliceIndex([]int{1000, 2000}) {
|
|
result = append(result, w)
|
|
if w == 2000 {
|
|
break
|
|
}
|
|
for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
|
|
for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
|
|
result = append(result, y)
|
|
for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
|
|
if z&1 == 1 {
|
|
continue
|
|
}
|
|
result = append(result, z)
|
|
if z >= 4 {
|
|
continue W // modified to be multilevel
|
|
}
|
|
}
|
|
result = append(result, -y) // should never be executed
|
|
}
|
|
result = append(result, x)
|
|
}
|
|
}
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func TestPanickyIterator1() {
|
|
var result []int
|
|
defer func() {
|
|
r := recover()
|
|
fmt.Println("Recovering", r)
|
|
}()
|
|
for _, z := range PanickyOfSliceIndex([]int{1, 2, 3, 4}) {
|
|
result = append(result, z)
|
|
if z == 4 {
|
|
break
|
|
}
|
|
}
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func TestPanickyIterator2() {
|
|
var result []int
|
|
defer func() {
|
|
r := recover()
|
|
fmt.Println("Recovering ", r)
|
|
}()
|
|
for _, x := range OfSliceIndex([]int{100, 200}) {
|
|
result = append(result, x)
|
|
Y:
|
|
// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
|
|
for _, y := range VeryBadOfSliceIndex([]int{10, 20}) {
|
|
result = append(result, y)
|
|
|
|
// converts early exit into a panic --> 1, 2
|
|
for k, z := range PanickyOfSliceIndex([]int{1, 2}) { // iterator panics
|
|
result = append(result, z)
|
|
if k == 1 {
|
|
break Y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPanickyIteratorWithNewDefer() {
|
|
var result []int
|
|
defer func() {
|
|
r := recover()
|
|
fmt.Println("Recovering ", r)
|
|
}()
|
|
for _, x := range OfSliceIndex([]int{100, 200}) {
|
|
result = append(result, x)
|
|
Y:
|
|
// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
|
|
for _, y := range VeryBadOfSliceIndex([]int{10, 20}) {
|
|
defer func() { // This defer will be set on TestPanickyIteratorWithNewDefer from TestPanickyIteratorWithNewDefer-range2
|
|
fmt.Println("y loop defer")
|
|
}()
|
|
result = append(result, y)
|
|
|
|
// converts early exit into a panic --> 1, 2
|
|
for k, z := range PanickyOfSliceIndex([]int{1, 2}) { // iterator panics
|
|
result = append(result, z)
|
|
if k == 1 {
|
|
break Y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLongReturnWrapper() {
|
|
TestLongReturn()
|
|
fmt.Println("returned")
|
|
}
|
|
|
|
func TestLongReturn() {
|
|
for _, x := range OfSliceIndex([]int{1, 2, 3}) {
|
|
for _, y := range OfSliceIndex([]int{10, 20, 30}) {
|
|
if y == 10 {
|
|
return
|
|
}
|
|
}
|
|
fmt.Println(x)
|
|
}
|
|
}
|
|
|
|
func TestGotoA1() {
|
|
result := []int{}
|
|
for _, x := range OfSliceIndex([]int{-1, -4, -5}) {
|
|
result = append(result, x)
|
|
if x == -4 {
|
|
break
|
|
}
|
|
for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
|
|
if y == 3 {
|
|
goto A
|
|
}
|
|
result = append(result, y)
|
|
}
|
|
A:
|
|
result = append(result, x)
|
|
}
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func TestGotoB1() {
|
|
result := []int{}
|
|
for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
|
|
result = append(result, x)
|
|
if x == -4 {
|
|
break
|
|
}
|
|
for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
|
|
if y == 3 {
|
|
goto B
|
|
}
|
|
result = append(result, y)
|
|
}
|
|
result = append(result, x)
|
|
}
|
|
B:
|
|
result = append(result, 999)
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func TestRecur(n int) {
|
|
result := []int{}
|
|
if n > 0 {
|
|
TestRecur(n - 1)
|
|
}
|
|
for _, x := range OfSliceIndex([]int{10, 20, 30}) {
|
|
result = append(result, x)
|
|
if n == 3 {
|
|
TestRecur(0)
|
|
}
|
|
}
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func main() {
|
|
TestTrickyIterAll()
|
|
TestTrickyIterAll2()
|
|
TestBreak1()
|
|
TestBreak2()
|
|
TestMultiCont0()
|
|
TestPanickyIterator1()
|
|
TestPanickyIterator2()
|
|
TestPanickyIteratorWithNewDefer()
|
|
TestLongReturnWrapper()
|
|
TestGotoA1()
|
|
TestGotoB1()
|
|
TestRecur(3)
|
|
}
|
|
|
|
type Seq[T any] func(yield func(T) bool)
|
|
type Seq2[T1, T2 any] func(yield func(T1, T2) bool)
|
|
|
|
type TrickyIterator struct {
|
|
yield func()
|
|
}
|
|
|
|
func (ti *TrickyIterator) iterAll(s []int) Seq2[int, int] {
|
|
return func(yield func(int, int) bool) {
|
|
// NOTE: storing the yield func in the iterator has been removed because
|
|
// it make the closure escape to the heap which breaks the .closureptr
|
|
// heuristic. Eventually we will need to figure out what to do when that
|
|
// happens.
|
|
// ti.yield = yield // Save yield for future abuse
|
|
for i, v := range s {
|
|
if !yield(i, v) {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
// OfSliceIndex returns a Seq2 over the elements of s. It is equivalent
|
|
// to range s.
|
|
func OfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
|
|
return func(yield func(int, T) bool) {
|
|
for i, v := range s {
|
|
if !yield(i, v) {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
// PanickyOfSliceIndex iterates the slice but panics if it exits the loop early
|
|
func PanickyOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
|
|
return func(yield func(int, T) bool) {
|
|
for i, v := range s {
|
|
if !yield(i, v) {
|
|
panic(fmt.Errorf("Panicky iterator panicking"))
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
// VeryBadOfSliceIndex is "very bad" because it ignores the return value from yield
|
|
// and just keeps on iterating, and also wraps that call in a defer-recover so it can
|
|
// keep on trying after the first panic.
|
|
func VeryBadOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
|
|
return func(yield func(int, T) bool) {
|
|
for i, v := range s {
|
|
func() {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
yield(i, v)
|
|
}()
|
|
}
|
|
return
|
|
}
|
|
}
|