Source file src/cmd/compile/internal/rangefunc/rangefunc_test.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package rangefunc_test
     6  
     7  import (
     8  	"fmt"
     9  	"regexp"
    10  	"slices"
    11  	"testing"
    12  )
    13  
    14  type Seq[T any] func(yield func(T) bool)
    15  type Seq2[T1, T2 any] func(yield func(T1, T2) bool)
    16  
    17  // OfSliceIndex returns a Seq2 over the elements of s. It is equivalent
    18  // to range s.
    19  func OfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    20  	return func(yield func(int, T) bool) {
    21  		for i, v := range s {
    22  			if !yield(i, v) {
    23  				return
    24  			}
    25  		}
    26  		return
    27  	}
    28  }
    29  
    30  // BadOfSliceIndex is "bad" because it ignores the return value from yield
    31  // and just keeps on iterating.
    32  func BadOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    33  	return func(yield func(int, T) bool) {
    34  		for i, v := range s {
    35  			yield(i, v)
    36  		}
    37  		return
    38  	}
    39  }
    40  
    41  // VeryBadOfSliceIndex is "very bad" because it ignores the return value from yield
    42  // and just keeps on iterating, and also wraps that call in a defer-recover so it can
    43  // keep on trying after the first panic.
    44  func VeryBadOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    45  	return func(yield func(int, T) bool) {
    46  		for i, v := range s {
    47  			func() {
    48  				defer func() {
    49  					recover()
    50  				}()
    51  				yield(i, v)
    52  			}()
    53  		}
    54  		return
    55  	}
    56  }
    57  
    58  // SwallowPanicOfSliceIndex hides panics and converts them to normal return
    59  func SwallowPanicOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    60  	return func(yield func(int, T) bool) {
    61  		for i, v := range s {
    62  			done := false
    63  			func() {
    64  				defer func() {
    65  					if r := recover(); r != nil {
    66  						done = true
    67  					}
    68  				}()
    69  				done = !yield(i, v)
    70  			}()
    71  			if done {
    72  				return
    73  			}
    74  		}
    75  		return
    76  	}
    77  }
    78  
    79  // PanickyOfSliceIndex iterates the slice but panics if it exits the loop early
    80  func PanickyOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    81  	return func(yield func(int, T) bool) {
    82  		for i, v := range s {
    83  			if !yield(i, v) {
    84  				panic(fmt.Errorf("Panicky iterator panicking"))
    85  			}
    86  		}
    87  		return
    88  	}
    89  }
    90  
    91  // CooperativeBadOfSliceIndex calls the loop body from a goroutine after
    92  // a ping on a channel, and returns recover()on that same channel.
    93  func CooperativeBadOfSliceIndex[T any, S ~[]T](s S, proceed chan any) Seq2[int, T] {
    94  	return func(yield func(int, T) bool) {
    95  		for i, v := range s {
    96  			if !yield(i, v) {
    97  				// if the body breaks, call yield just once in a goroutine
    98  				go func() {
    99  					<-proceed
   100  					defer func() {
   101  						proceed <- recover()
   102  					}()
   103  					yield(0, s[0])
   104  				}()
   105  				return
   106  			}
   107  		}
   108  		return
   109  	}
   110  }
   111  
   112  // TrickyIterator is a type intended to test whether an iterator that
   113  // calls a yield function after loop exit must inevitably escape the
   114  // closure; this might be relevant to future checking/optimization.
   115  type TrickyIterator struct {
   116  	yield func(int, int) bool
   117  }
   118  
   119  func (ti *TrickyIterator) iterEcho(s []int) Seq2[int, int] {
   120  	return func(yield func(int, int) bool) {
   121  		for i, v := range s {
   122  			if !yield(i, v) {
   123  				ti.yield = yield
   124  				return
   125  			}
   126  			if ti.yield != nil && !ti.yield(i, v) {
   127  				return
   128  			}
   129  		}
   130  		ti.yield = yield
   131  		return
   132  	}
   133  }
   134  
   135  func (ti *TrickyIterator) iterAll(s []int) Seq2[int, int] {
   136  	return func(yield func(int, int) bool) {
   137  		ti.yield = yield // Save yield for future abuse
   138  		for i, v := range s {
   139  			if !yield(i, v) {
   140  				return
   141  			}
   142  		}
   143  		return
   144  	}
   145  }
   146  
   147  func (ti *TrickyIterator) iterOne(s []int) Seq2[int, int] {
   148  	return func(yield func(int, int) bool) {
   149  		ti.yield = yield // Save yield for future abuse
   150  		if len(s) > 0 {  // Not in a loop might escape differently
   151  			yield(0, s[0])
   152  		}
   153  		return
   154  	}
   155  }
   156  
   157  func (ti *TrickyIterator) iterZero(s []int) Seq2[int, int] {
   158  	return func(yield func(int, int) bool) {
   159  		ti.yield = yield // Save yield for future abuse
   160  		// Don't call it at all, maybe it won't escape
   161  		return
   162  	}
   163  }
   164  
   165  func (ti *TrickyIterator) fail() {
   166  	if ti.yield != nil {
   167  		ti.yield(1, 1)
   168  	}
   169  }
   170  
   171  const DONE = 0      // body of loop has exited in a non-panic way
   172  const READY = 1     // body of loop has not exited yet, is not running
   173  const PANIC = 2     // body of loop is either currently running, or has panicked
   174  const EXHAUSTED = 3 // iterator function return, i.e., sequence is "exhausted"
   175  
   176  const MISSING_PANIC = 4 // overload "READY" for panic call
   177  
   178  // Check2 wraps the function body passed to iterator forall
   179  // in code that ensures that it cannot (successfully) be called
   180  // either after body return false (control flow out of loop) or
   181  // forall itself returns (the iteration is now done).
   182  //
   183  // Note that this can catch errors before the inserted checks.
   184  func Check2[U, V any](forall Seq2[U, V]) Seq2[U, V] {
   185  	return func(body func(U, V) bool) {
   186  		state := READY
   187  		forall(func(u U, v V) bool {
   188  			if state != READY {
   189  				panic(fail[state])
   190  			}
   191  			state = PANIC
   192  			ret := body(u, v)
   193  			if ret {
   194  				state = READY
   195  			} else {
   196  				state = DONE
   197  			}
   198  			return ret
   199  		})
   200  		if state == PANIC {
   201  			panic(fail[MISSING_PANIC])
   202  		}
   203  		state = EXHAUSTED
   204  	}
   205  }
   206  
   207  func Check[U any](forall Seq[U]) Seq[U] {
   208  	return func(body func(U) bool) {
   209  		state := READY
   210  		forall(func(u U) bool {
   211  			if state != READY {
   212  				panic(fail[state])
   213  			}
   214  			state = PANIC
   215  			ret := body(u)
   216  			if ret {
   217  				state = READY
   218  			} else {
   219  				state = DONE
   220  			}
   221  			return ret
   222  		})
   223  		if state == PANIC {
   224  			panic(fail[MISSING_PANIC])
   225  		}
   226  		state = EXHAUSTED
   227  	}
   228  }
   229  
   230  func matchError(r any, x string) bool {
   231  	if r == nil {
   232  		return false
   233  	}
   234  	if x == "" {
   235  		return true
   236  	}
   237  	if p, ok := r.(errorString); ok {
   238  		return p.Error() == x
   239  	}
   240  	if p, ok := r.(error); ok {
   241  		e, err := regexp.Compile(x)
   242  		if err != nil {
   243  			panic(fmt.Errorf("Bad regexp '%s' passed to matchError", x))
   244  		}
   245  		return e.MatchString(p.Error())
   246  	}
   247  	return false
   248  }
   249  
   250  func matchErrorHelper(t *testing.T, r any, x string) {
   251  	if matchError(r, x) {
   252  		t.Logf("Saw expected panic '%v'", r)
   253  	} else {
   254  		t.Errorf("Saw wrong panic '%v', expected '%s'", r, x)
   255  	}
   256  }
   257  
   258  // An errorString represents a runtime error described by a single string.
   259  type errorString string
   260  
   261  func (e errorString) Error() string {
   262  	return string(e)
   263  }
   264  
   265  const (
   266  	// RERR_ is for runtime error, and may be regexps/substrings, to simplify use of tests with tools
   267  	RERR_DONE      = "runtime error: range function continued iteration after function for loop body returned false"
   268  	RERR_PANIC     = "runtime error: range function continued iteration after loop body panic"
   269  	RERR_EXHAUSTED = "runtime error: range function continued iteration after whole loop exit"
   270  	RERR_MISSING   = "runtime error: range function recovered a loop body panic and did not resume panicking"
   271  
   272  	// CERR_ is for checked errors in the Check combinator defined above, and should be literal strings
   273  	CERR_PFX       = "checked rangefunc error: "
   274  	CERR_DONE      = CERR_PFX + "loop iteration after body done"
   275  	CERR_PANIC     = CERR_PFX + "loop iteration after panic"
   276  	CERR_EXHAUSTED = CERR_PFX + "loop iteration after iterator exit"
   277  	CERR_MISSING   = CERR_PFX + "loop iterator swallowed panic"
   278  )
   279  
   280  var fail []error = []error{
   281  	errorString(CERR_DONE),
   282  	errorString(CERR_PFX + "loop iterator, unexpected error"),
   283  	errorString(CERR_PANIC),
   284  	errorString(CERR_EXHAUSTED),
   285  	errorString(CERR_MISSING),
   286  }
   287  
   288  func TestCheck(t *testing.T) {
   289  	i := 0
   290  	defer func() {
   291  		if r := recover(); r != nil {
   292  			if matchError(r, CERR_DONE) {
   293  				t.Logf("Saw expected panic '%v'", r)
   294  			} else {
   295  				t.Errorf("Saw wrong panic '%v'", r)
   296  			}
   297  		} else {
   298  			t.Error("Wanted to see a failure")
   299  		}
   300  	}()
   301  	for _, x := range Check2(BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) {
   302  		i += x
   303  		if i > 4*9 {
   304  			break
   305  		}
   306  	}
   307  }
   308  
   309  func TestCooperativeBadOfSliceIndex(t *testing.T) {
   310  	i := 0
   311  	proceed := make(chan any)
   312  	for _, x := range CooperativeBadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, proceed) {
   313  		i += x
   314  		if i >= 36 {
   315  			break
   316  		}
   317  	}
   318  	proceed <- true
   319  	if r := <-proceed; r != nil {
   320  		if matchError(r, RERR_EXHAUSTED) {
   321  			t.Logf("Saw expected panic '%v'", r)
   322  		} else {
   323  			t.Errorf("Saw wrong panic '%v'", r)
   324  		}
   325  	} else {
   326  		t.Error("Wanted to see a failure")
   327  	}
   328  	if i != 36 {
   329  		t.Errorf("Expected i == 36, saw %d instead", i)
   330  	} else {
   331  		t.Logf("i = %d", i)
   332  	}
   333  }
   334  
   335  func TestCooperativeBadOfSliceIndexCheck(t *testing.T) {
   336  	i := 0
   337  	proceed := make(chan any)
   338  	for _, x := range Check2(CooperativeBadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, proceed)) {
   339  		i += x
   340  		if i >= 36 {
   341  			break
   342  		}
   343  	}
   344  	proceed <- true
   345  	if r := <-proceed; r != nil {
   346  		if matchError(r, CERR_EXHAUSTED) {
   347  			t.Logf("Saw expected panic '%v'", r)
   348  		} else {
   349  			t.Errorf("Saw wrong panic '%v'", r)
   350  		}
   351  
   352  	} else {
   353  		t.Error("Wanted to see a failure")
   354  	}
   355  	if i != 36 {
   356  		t.Errorf("Expected i == 36, saw %d instead", i)
   357  	} else {
   358  		t.Logf("i = %d", i)
   359  	}
   360  }
   361  
   362  func TestTrickyIterAll(t *testing.T) {
   363  	trickItAll := TrickyIterator{}
   364  	i := 0
   365  	for _, x := range trickItAll.iterAll([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   366  		i += x
   367  		if i >= 36 {
   368  			break
   369  		}
   370  	}
   371  
   372  	if i != 36 {
   373  		t.Errorf("Expected i == 36, saw %d instead", i)
   374  	} else {
   375  		t.Logf("i = %d", i)
   376  	}
   377  
   378  	defer func() {
   379  		if r := recover(); r != nil {
   380  			if matchError(r, RERR_EXHAUSTED) {
   381  				t.Logf("Saw expected panic '%v'", r)
   382  			} else {
   383  				t.Errorf("Saw wrong panic '%v'", r)
   384  			}
   385  		} else {
   386  			t.Error("Wanted to see a failure")
   387  		}
   388  	}()
   389  
   390  	trickItAll.fail()
   391  }
   392  
   393  func TestTrickyIterOne(t *testing.T) {
   394  	trickItOne := TrickyIterator{}
   395  	i := 0
   396  	for _, x := range trickItOne.iterOne([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   397  		i += x
   398  		if i >= 36 {
   399  			break
   400  		}
   401  	}
   402  
   403  	// Don't care about value, ought to be 36 anyhow.
   404  	t.Logf("i = %d", i)
   405  
   406  	defer func() {
   407  		if r := recover(); r != nil {
   408  			if matchError(r, RERR_EXHAUSTED) {
   409  				t.Logf("Saw expected panic '%v'", r)
   410  			} else {
   411  				t.Errorf("Saw wrong panic '%v'", r)
   412  			}
   413  		} else {
   414  			t.Error("Wanted to see a failure")
   415  		}
   416  	}()
   417  
   418  	trickItOne.fail()
   419  }
   420  
   421  func TestTrickyIterZero(t *testing.T) {
   422  	trickItZero := TrickyIterator{}
   423  	i := 0
   424  	for _, x := range trickItZero.iterZero([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   425  		i += x
   426  		if i >= 36 {
   427  			break
   428  		}
   429  	}
   430  
   431  	// Don't care about value, ought to be 0 anyhow.
   432  	t.Logf("i = %d", i)
   433  
   434  	defer func() {
   435  		if r := recover(); r != nil {
   436  			if matchError(r, RERR_EXHAUSTED) {
   437  				t.Logf("Saw expected panic '%v'", r)
   438  			} else {
   439  				t.Errorf("Saw wrong panic '%v'", r)
   440  			}
   441  		} else {
   442  			t.Error("Wanted to see a failure")
   443  		}
   444  	}()
   445  
   446  	trickItZero.fail()
   447  }
   448  
   449  func TestTrickyIterZeroCheck(t *testing.T) {
   450  	trickItZero := TrickyIterator{}
   451  	i := 0
   452  	for _, x := range Check2(trickItZero.iterZero([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) {
   453  		i += x
   454  		if i >= 36 {
   455  			break
   456  		}
   457  	}
   458  
   459  	// Don't care about value, ought to be 0 anyhow.
   460  	t.Logf("i = %d", i)
   461  
   462  	defer func() {
   463  		if r := recover(); r != nil {
   464  			if matchError(r, CERR_EXHAUSTED) {
   465  				t.Logf("Saw expected panic '%v'", r)
   466  			} else {
   467  				t.Errorf("Saw wrong panic '%v'", r)
   468  			}
   469  		} else {
   470  			t.Error("Wanted to see a failure")
   471  		}
   472  	}()
   473  
   474  	trickItZero.fail()
   475  }
   476  
   477  func TestTrickyIterEcho(t *testing.T) {
   478  	trickItAll := TrickyIterator{}
   479  	i := 0
   480  	for _, x := range trickItAll.iterAll([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   481  		t.Logf("first loop i=%d", i)
   482  		i += x
   483  		if i >= 10 {
   484  			break
   485  		}
   486  	}
   487  
   488  	if i != 10 {
   489  		t.Errorf("Expected i == 10, saw %d instead", i)
   490  	} else {
   491  		t.Logf("i = %d", i)
   492  	}
   493  
   494  	defer func() {
   495  		if r := recover(); r != nil {
   496  			if matchError(r, RERR_EXHAUSTED) {
   497  				t.Logf("Saw expected panic '%v'", r)
   498  			} else {
   499  				t.Errorf("Saw wrong panic '%v'", r)
   500  			}
   501  		} else {
   502  			t.Error("Wanted to see a failure")
   503  		}
   504  	}()
   505  
   506  	i = 0
   507  	for _, x := range trickItAll.iterEcho([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   508  		t.Logf("second loop i=%d", i)
   509  		if x >= 5 {
   510  			break
   511  		}
   512  	}
   513  
   514  }
   515  
   516  func TestTrickyIterEcho2(t *testing.T) {
   517  	trickItAll := TrickyIterator{}
   518  	var i int
   519  
   520  	defer func() {
   521  		if r := recover(); r != nil {
   522  			if matchError(r, RERR_EXHAUSTED) {
   523  				t.Logf("Saw expected panic '%v'", r)
   524  			} else {
   525  				t.Errorf("Saw wrong panic '%v'", r)
   526  			}
   527  		} else {
   528  			t.Error("Wanted to see a failure")
   529  		}
   530  	}()
   531  
   532  	for k := range 2 {
   533  		i = 0
   534  		for _, x := range trickItAll.iterEcho([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   535  			t.Logf("k,x,i=%d,%d,%d", k, x, i)
   536  			i += x
   537  			if i >= 10 {
   538  				break
   539  			}
   540  		}
   541  		t.Logf("i = %d", i)
   542  
   543  		if i != 10 {
   544  			t.Errorf("Expected i == 10, saw %d instead", i)
   545  		}
   546  	}
   547  }
   548  
   549  // TestBreak1 should just work, with well-behaved iterators.
   550  // (The misbehaving iterator detector should not trigger.)
   551  func TestBreak1(t *testing.T) {
   552  	var result []int
   553  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3}
   554  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4}) {
   555  		if x == -4 {
   556  			break
   557  		}
   558  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   559  			if y == 3 {
   560  				break
   561  			}
   562  			result = append(result, y)
   563  		}
   564  		result = append(result, x)
   565  	}
   566  	if !slices.Equal(expect, result) {
   567  		t.Errorf("Expected %v, got %v", expect, result)
   568  	}
   569  }
   570  
   571  // TestBreak2 should just work, with well-behaved iterators.
   572  // (The misbehaving iterator detector should not trigger.)
   573  func TestBreak2(t *testing.T) {
   574  	var result []int
   575  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3}
   576  outer:
   577  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4}) {
   578  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   579  			if y == 3 {
   580  				break
   581  			}
   582  			if x == -4 {
   583  				break outer
   584  			}
   585  
   586  			result = append(result, y)
   587  		}
   588  		result = append(result, x)
   589  	}
   590  	if !slices.Equal(expect, result) {
   591  		t.Errorf("Expected %v, got %v", expect, result)
   592  	}
   593  }
   594  
   595  // TestContinue should just work, with well-behaved iterators.
   596  // (The misbehaving iterator detector should not trigger.)
   597  func TestContinue(t *testing.T) {
   598  	var result []int
   599  	var expect = []int{-1, 1, 2, -2, 1, 2, -3, 1, 2, -4}
   600  outer:
   601  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4}) {
   602  		result = append(result, x)
   603  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   604  			if y == 3 {
   605  				continue outer
   606  			}
   607  			if x == -4 {
   608  				break outer
   609  			}
   610  
   611  			result = append(result, y)
   612  		}
   613  		result = append(result, x-10)
   614  	}
   615  	if !slices.Equal(expect, result) {
   616  		t.Errorf("Expected %v, got %v", expect, result)
   617  	}
   618  }
   619  
   620  // TestBreak3 should just work, with well-behaved iterators.
   621  // (The misbehaving iterator detector should not trigger.)
   622  func TestBreak3(t *testing.T) {
   623  	var result []int
   624  	var expect = []int{100, 10, 2, 4, 200, 10, 2, 4, 20, 2, 4, 300, 10, 2, 4, 20, 2, 4, 30}
   625  X:
   626  	for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   627  	Y:
   628  		for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   629  			if 10*y >= x {
   630  				break
   631  			}
   632  			result = append(result, y)
   633  			if y == 30 {
   634  				continue X
   635  			}
   636  		Z:
   637  			for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   638  				if z&1 == 1 {
   639  					continue Z
   640  				}
   641  				result = append(result, z)
   642  				if z >= 4 {
   643  					continue Y
   644  				}
   645  			}
   646  			result = append(result, -y) // should never be executed
   647  		}
   648  		result = append(result, x)
   649  	}
   650  	if !slices.Equal(expect, result) {
   651  		t.Errorf("Expected %v, got %v", expect, result)
   652  	}
   653  }
   654  
   655  // TestBreak1BadA should end in a panic when the outer-loop's
   656  // single-level break is ignore by BadOfSliceIndex
   657  func TestBreak1BadA(t *testing.T) {
   658  	var result []int
   659  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3}
   660  
   661  	defer func() {
   662  		if r := recover(); r != nil {
   663  			if matchError(r, RERR_DONE) {
   664  				t.Logf("Saw expected panic '%v'", r)
   665  			} else {
   666  				t.Errorf("Saw wrong panic '%v'", r)
   667  			}
   668  			if !slices.Equal(expect, result) {
   669  				t.Errorf("Expected %v, got %v", expect, result)
   670  			}
   671  		} else {
   672  			t.Error("Wanted to see a failure")
   673  		}
   674  	}()
   675  
   676  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   677  		if x == -4 {
   678  			break
   679  		}
   680  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   681  			if y == 3 {
   682  				break
   683  			}
   684  			result = append(result, y)
   685  		}
   686  		result = append(result, x)
   687  	}
   688  }
   689  
   690  // TestBreak1BadB should end in a panic, sooner, when the inner-loop's
   691  // (nested) single-level break is ignored by BadOfSliceIndex
   692  func TestBreak1BadB(t *testing.T) {
   693  	var result []int
   694  	var expect = []int{1, 2} // inner breaks, panics, after before outer appends
   695  
   696  	defer func() {
   697  		if r := recover(); r != nil {
   698  			if matchError(r, RERR_DONE) {
   699  				t.Logf("Saw expected panic '%v'", r)
   700  			} else {
   701  				t.Errorf("Saw wrong panic '%v'", r)
   702  			}
   703  			if !slices.Equal(expect, result) {
   704  				t.Errorf("Expected %v, got %v", expect, result)
   705  			}
   706  		} else {
   707  			t.Error("Wanted to see a failure")
   708  		}
   709  	}()
   710  
   711  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   712  		if x == -4 {
   713  			break
   714  		}
   715  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   716  			if y == 3 {
   717  				break
   718  			}
   719  			result = append(result, y)
   720  		}
   721  		result = append(result, x)
   722  	}
   723  }
   724  
   725  // TestMultiCont0 tests multilevel continue with no bad iterators
   726  // (it should just work)
   727  func TestMultiCont0(t *testing.T) {
   728  	var result []int
   729  	var expect = []int{1000, 10, 2, 4, 2000}
   730  
   731  W:
   732  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   733  		result = append(result, w)
   734  		if w == 2000 {
   735  			break
   736  		}
   737  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   738  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   739  				result = append(result, y)
   740  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   741  					if z&1 == 1 {
   742  						continue
   743  					}
   744  					result = append(result, z)
   745  					if z >= 4 {
   746  						continue W // modified to be multilevel
   747  					}
   748  				}
   749  				result = append(result, -y) // should never be executed
   750  			}
   751  			result = append(result, x)
   752  		}
   753  	}
   754  	if !slices.Equal(expect, result) {
   755  		t.Errorf("Expected %v, got %v", expect, result)
   756  	}
   757  }
   758  
   759  // TestMultiCont1 tests multilevel continue with a bad iterator
   760  // in the outermost loop exited by the continue.
   761  func TestMultiCont1(t *testing.T) {
   762  	var result []int
   763  	var expect = []int{1000, 10, 2, 4}
   764  	defer func() {
   765  		if r := recover(); r != nil {
   766  			if matchError(r, RERR_DONE) {
   767  				t.Logf("Saw expected panic '%v'", r)
   768  			} else {
   769  				t.Errorf("Saw wrong panic '%v'", r)
   770  			}
   771  			if !slices.Equal(expect, result) {
   772  				t.Errorf("Expected %v, got %v", expect, result)
   773  			}
   774  		} else {
   775  			t.Errorf("Wanted to see a failure, result was %v", result)
   776  		}
   777  	}()
   778  
   779  W:
   780  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   781  		result = append(result, w)
   782  		if w == 2000 {
   783  			break
   784  		}
   785  		for _, x := range BadOfSliceIndex([]int{100, 200, 300, 400}) {
   786  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   787  				result = append(result, y)
   788  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   789  					if z&1 == 1 {
   790  						continue
   791  					}
   792  					result = append(result, z)
   793  					if z >= 4 {
   794  						continue W
   795  					}
   796  				}
   797  				result = append(result, -y) // should never be executed
   798  			}
   799  			result = append(result, x)
   800  		}
   801  	}
   802  	if !slices.Equal(expect, result) {
   803  		t.Errorf("Expected %v, got %v", expect, result)
   804  	}
   805  }
   806  
   807  // TestMultiCont2 tests multilevel continue with a bad iterator
   808  // in a middle loop exited by the continue.
   809  func TestMultiCont2(t *testing.T) {
   810  	var result []int
   811  	var expect = []int{1000, 10, 2, 4}
   812  	defer func() {
   813  		if r := recover(); r != nil {
   814  			if matchError(r, RERR_DONE) {
   815  				t.Logf("Saw expected panic '%v'", r)
   816  			} else {
   817  				t.Errorf("Saw wrong panic '%v'", r)
   818  			}
   819  			if !slices.Equal(expect, result) {
   820  				t.Errorf("Expected %v, got %v", expect, result)
   821  			}
   822  		} else {
   823  			t.Errorf("Wanted to see a failure, result was %v", result)
   824  		}
   825  	}()
   826  
   827  W:
   828  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   829  		result = append(result, w)
   830  		if w == 2000 {
   831  			break
   832  		}
   833  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   834  			for _, y := range BadOfSliceIndex([]int{10, 20, 30, 40}) {
   835  				result = append(result, y)
   836  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   837  					if z&1 == 1 {
   838  						continue
   839  					}
   840  					result = append(result, z)
   841  					if z >= 4 {
   842  						continue W
   843  					}
   844  				}
   845  				result = append(result, -y) // should never be executed
   846  			}
   847  			result = append(result, x)
   848  		}
   849  	}
   850  	if !slices.Equal(expect, result) {
   851  		t.Errorf("Expected %v, got %v", expect, result)
   852  	}
   853  }
   854  
   855  // TestMultiCont3 tests multilevel continue with a bad iterator
   856  // in the innermost loop exited by the continue.
   857  func TestMultiCont3(t *testing.T) {
   858  	var result []int
   859  	var expect = []int{1000, 10, 2, 4}
   860  	defer func() {
   861  		if r := recover(); r != nil {
   862  			if matchError(r, RERR_DONE) {
   863  				t.Logf("Saw expected panic '%v'", r)
   864  			} else {
   865  				t.Errorf("Saw wrong panic '%v'", r)
   866  			}
   867  			if !slices.Equal(expect, result) {
   868  				t.Errorf("Expected %v, got %v", expect, result)
   869  			}
   870  		} else {
   871  			t.Errorf("Wanted to see a failure, result was %v", result)
   872  		}
   873  	}()
   874  
   875  W:
   876  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   877  		result = append(result, w)
   878  		if w == 2000 {
   879  			break
   880  		}
   881  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   882  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   883  				result = append(result, y)
   884  				for _, z := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   885  					if z&1 == 1 {
   886  						continue
   887  					}
   888  					result = append(result, z)
   889  					if z >= 4 {
   890  						continue W
   891  					}
   892  				}
   893  				result = append(result, -y) // should never be executed
   894  			}
   895  			result = append(result, x)
   896  		}
   897  	}
   898  	if !slices.Equal(expect, result) {
   899  		t.Errorf("Expected %v, got %v", expect, result)
   900  	}
   901  }
   902  
   903  // TestMultiBreak0 tests multilevel break with a bad iterator
   904  // in the outermost loop exited by the break (the outermost loop).
   905  func TestMultiBreak0(t *testing.T) {
   906  	var result []int
   907  	var expect = []int{1000, 10, 2, 4}
   908  	defer func() {
   909  		if r := recover(); r != nil {
   910  			if matchError(r, RERR_DONE) {
   911  				t.Logf("Saw expected panic '%v'", r)
   912  			} else {
   913  				t.Errorf("Saw wrong panic '%v'", r)
   914  			}
   915  			if !slices.Equal(expect, result) {
   916  				t.Errorf("Expected %v, got %v", expect, result)
   917  			}
   918  		} else {
   919  			t.Errorf("Wanted to see a failure, result was %v", result)
   920  		}
   921  	}()
   922  
   923  W:
   924  	for _, w := range BadOfSliceIndex([]int{1000, 2000}) {
   925  		result = append(result, w)
   926  		if w == 2000 {
   927  			break
   928  		}
   929  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   930  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   931  				result = append(result, y)
   932  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   933  					if z&1 == 1 {
   934  						continue
   935  					}
   936  					result = append(result, z)
   937  					if z >= 4 {
   938  						break W
   939  					}
   940  				}
   941  				result = append(result, -y) // should never be executed
   942  			}
   943  			result = append(result, x)
   944  		}
   945  	}
   946  	if !slices.Equal(expect, result) {
   947  		t.Errorf("Expected %v, got %v", expect, result)
   948  	}
   949  }
   950  
   951  // TestMultiBreak1 tests multilevel break with a bad iterator
   952  // in an intermediate loop exited by the break.
   953  func TestMultiBreak1(t *testing.T) {
   954  	var result []int
   955  	var expect = []int{1000, 10, 2, 4}
   956  	defer func() {
   957  		if r := recover(); r != nil {
   958  			if matchError(r, RERR_DONE) {
   959  				t.Logf("Saw expected panic '%v'", r)
   960  			} else {
   961  				t.Errorf("Saw wrong panic '%v'", r)
   962  			}
   963  			if !slices.Equal(expect, result) {
   964  				t.Errorf("Expected %v, got %v", expect, result)
   965  			}
   966  		} else {
   967  			t.Errorf("Wanted to see a failure, result was %v", result)
   968  		}
   969  	}()
   970  
   971  W:
   972  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   973  		result = append(result, w)
   974  		if w == 2000 {
   975  			break
   976  		}
   977  		for _, x := range BadOfSliceIndex([]int{100, 200, 300, 400}) {
   978  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   979  				result = append(result, y)
   980  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   981  					if z&1 == 1 {
   982  						continue
   983  					}
   984  					result = append(result, z)
   985  					if z >= 4 {
   986  						break W
   987  					}
   988  				}
   989  				result = append(result, -y) // should never be executed
   990  			}
   991  			result = append(result, x)
   992  		}
   993  	}
   994  	if !slices.Equal(expect, result) {
   995  		t.Errorf("Expected %v, got %v", expect, result)
   996  	}
   997  }
   998  
   999  // TestMultiBreak2 tests multilevel break with two bad iterators
  1000  // in intermediate loops exited by the break.
  1001  func TestMultiBreak2(t *testing.T) {
  1002  	var result []int
  1003  	var expect = []int{1000, 10, 2, 4}
  1004  	defer func() {
  1005  		if r := recover(); r != nil {
  1006  			if matchError(r, RERR_DONE) {
  1007  				t.Logf("Saw expected panic '%v'", r)
  1008  			} else {
  1009  				t.Errorf("Saw wrong panic '%v'", r)
  1010  			}
  1011  			if !slices.Equal(expect, result) {
  1012  				t.Errorf("Expected %v, got %v", expect, result)
  1013  			}
  1014  		} else {
  1015  			t.Errorf("Wanted to see a failure, result was %v", result)
  1016  		}
  1017  	}()
  1018  
  1019  W:
  1020  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
  1021  		result = append(result, w)
  1022  		if w == 2000 {
  1023  			break
  1024  		}
  1025  		for _, x := range BadOfSliceIndex([]int{100, 200, 300, 400}) {
  1026  			for _, y := range BadOfSliceIndex([]int{10, 20, 30, 40}) {
  1027  				result = append(result, y)
  1028  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1029  					if z&1 == 1 {
  1030  						continue
  1031  					}
  1032  					result = append(result, z)
  1033  					if z >= 4 {
  1034  						break W
  1035  					}
  1036  				}
  1037  				result = append(result, -y) // should never be executed
  1038  			}
  1039  			result = append(result, x)
  1040  		}
  1041  	}
  1042  	if !slices.Equal(expect, result) {
  1043  		t.Errorf("Expected %v, got %v", expect, result)
  1044  	}
  1045  }
  1046  
  1047  // TestMultiBreak3 tests multilevel break with the bad iterator
  1048  // in the innermost loop exited by the break.
  1049  func TestMultiBreak3(t *testing.T) {
  1050  	var result []int
  1051  	var expect = []int{1000, 10, 2, 4}
  1052  	defer func() {
  1053  		if r := recover(); r != nil {
  1054  			if matchError(r, RERR_DONE) {
  1055  				t.Logf("Saw expected panic '%v'", r)
  1056  			} else {
  1057  				t.Errorf("Saw wrong panic '%v'", r)
  1058  			}
  1059  			if !slices.Equal(expect, result) {
  1060  				t.Errorf("Expected %v, got %v", expect, result)
  1061  			}
  1062  		} else {
  1063  			t.Errorf("Wanted to see a failure, result was %v", result)
  1064  		}
  1065  	}()
  1066  
  1067  W:
  1068  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
  1069  		result = append(result, w)
  1070  		if w == 2000 {
  1071  			break
  1072  		}
  1073  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
  1074  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
  1075  				result = append(result, y)
  1076  				for _, z := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1077  					if z&1 == 1 {
  1078  						continue
  1079  					}
  1080  					result = append(result, z)
  1081  					if z >= 4 {
  1082  						break W
  1083  					}
  1084  				}
  1085  				result = append(result, -y) // should never be executed
  1086  			}
  1087  			result = append(result, x)
  1088  		}
  1089  	}
  1090  	if !slices.Equal(expect, result) {
  1091  		t.Errorf("Expected %v, got %v", expect, result)
  1092  	}
  1093  }
  1094  
  1095  func TestPanickyIterator1(t *testing.T) {
  1096  	var result []int
  1097  	var expect = []int{1, 2, 3, 4}
  1098  	defer func() {
  1099  		if r := recover(); r != nil {
  1100  			if matchError(r, "Panicky iterator panicking") {
  1101  				t.Logf("Saw expected panic '%v'", r)
  1102  			} else {
  1103  				t.Errorf("Saw wrong panic '%v'", r)
  1104  			}
  1105  		} else {
  1106  			t.Errorf("Wanted to see a failure, result was %v", result)
  1107  		}
  1108  		if !slices.Equal(expect, result) {
  1109  			t.Errorf("Expected %v, got %v", expect, result)
  1110  		}
  1111  	}()
  1112  	for _, z := range PanickyOfSliceIndex([]int{1, 2, 3, 4}) {
  1113  		result = append(result, z)
  1114  		if z == 4 {
  1115  			break
  1116  		}
  1117  	}
  1118  }
  1119  
  1120  func TestPanickyIterator1Check(t *testing.T) {
  1121  	var result []int
  1122  	var expect = []int{1, 2, 3, 4}
  1123  	defer func() {
  1124  		if r := recover(); r != nil {
  1125  			if matchError(r, "Panicky iterator panicking") {
  1126  				t.Logf("Saw expected panic '%v'", r)
  1127  			} else {
  1128  				t.Errorf("Saw wrong panic '%v'", r)
  1129  			}
  1130  			if !slices.Equal(expect, result) {
  1131  				t.Errorf("Expected %v, got %v", expect, result)
  1132  			}
  1133  		} else {
  1134  			t.Errorf("Wanted to see a failure, result was %v", result)
  1135  		}
  1136  	}()
  1137  	for _, z := range Check2(PanickyOfSliceIndex([]int{1, 2, 3, 4})) {
  1138  		result = append(result, z)
  1139  		if z == 4 {
  1140  			break
  1141  		}
  1142  	}
  1143  }
  1144  
  1145  func TestPanickyIterator2(t *testing.T) {
  1146  	var result []int
  1147  	var expect = []int{100, 10, 1, 2}
  1148  	defer func() {
  1149  		if r := recover(); r != nil {
  1150  			if matchError(r, RERR_MISSING) {
  1151  				t.Logf("Saw expected panic '%v'", r)
  1152  			} else {
  1153  				t.Errorf("Saw wrong panic '%v'", r)
  1154  			}
  1155  		} else {
  1156  			t.Errorf("Wanted to see a failure, result was %v", result)
  1157  		}
  1158  		if !slices.Equal(expect, result) {
  1159  			t.Errorf("Expected %v, got %v", expect, result)
  1160  		}
  1161  	}()
  1162  	for _, x := range OfSliceIndex([]int{100, 200}) {
  1163  		result = append(result, x)
  1164  	Y:
  1165  		// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
  1166  		for _, y := range VeryBadOfSliceIndex([]int{10, 20}) {
  1167  			result = append(result, y)
  1168  
  1169  			// converts early exit into a panic --> 1, 2
  1170  			for k, z := range PanickyOfSliceIndex([]int{1, 2}) { // iterator panics
  1171  				result = append(result, z)
  1172  				if k == 1 {
  1173  					break Y
  1174  				}
  1175  			}
  1176  		}
  1177  	}
  1178  }
  1179  
  1180  func TestPanickyIterator2Check(t *testing.T) {
  1181  	var result []int
  1182  	var expect = []int{100, 10, 1, 2}
  1183  	defer func() {
  1184  		if r := recover(); r != nil {
  1185  			if matchError(r, CERR_MISSING) {
  1186  				t.Logf("Saw expected panic '%v'", r)
  1187  			} else {
  1188  				t.Errorf("Saw wrong panic '%v'", r)
  1189  			}
  1190  		} else {
  1191  			t.Errorf("Wanted to see a failure, result was %v", result)
  1192  		}
  1193  		if !slices.Equal(expect, result) {
  1194  			t.Errorf("Expected %v, got %v", expect, result)
  1195  		}
  1196  	}()
  1197  	for _, x := range Check2(OfSliceIndex([]int{100, 200})) {
  1198  		result = append(result, x)
  1199  	Y:
  1200  		// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
  1201  		for _, y := range Check2(VeryBadOfSliceIndex([]int{10, 20})) {
  1202  			result = append(result, y)
  1203  
  1204  			// converts early exit into a panic --> 1, 2
  1205  			for k, z := range Check2(PanickyOfSliceIndex([]int{1, 2})) { // iterator panics
  1206  				result = append(result, z)
  1207  				if k == 1 {
  1208  					break Y
  1209  				}
  1210  			}
  1211  		}
  1212  	}
  1213  }
  1214  
  1215  func TestPanickyIterator3(t *testing.T) {
  1216  	var result []int
  1217  	var expect = []int{100, 10, 1, 2, 200, 10, 1, 2}
  1218  	defer func() {
  1219  		if r := recover(); r != nil {
  1220  			t.Errorf("Unexpected panic '%v'", r)
  1221  		}
  1222  		if !slices.Equal(expect, result) {
  1223  			t.Errorf("Expected %v, got %v", expect, result)
  1224  		}
  1225  	}()
  1226  	for _, x := range OfSliceIndex([]int{100, 200}) {
  1227  		result = append(result, x)
  1228  	Y:
  1229  		// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
  1230  		// This is cross-checked against the checked iterator below; the combinator should behave the same.
  1231  		for _, y := range VeryBadOfSliceIndex([]int{10, 20}) {
  1232  			result = append(result, y)
  1233  
  1234  			for k, z := range OfSliceIndex([]int{1, 2}) { // iterator does not panic
  1235  				result = append(result, z)
  1236  				if k == 1 {
  1237  					break Y
  1238  				}
  1239  			}
  1240  		}
  1241  	}
  1242  }
  1243  func TestPanickyIterator3Check(t *testing.T) {
  1244  	var result []int
  1245  	var expect = []int{100, 10, 1, 2, 200, 10, 1, 2}
  1246  	defer func() {
  1247  		if r := recover(); r != nil {
  1248  			t.Errorf("Unexpected panic '%v'", r)
  1249  		}
  1250  		if !slices.Equal(expect, result) {
  1251  			t.Errorf("Expected %v, got %v", expect, result)
  1252  		}
  1253  	}()
  1254  	for _, x := range Check2(OfSliceIndex([]int{100, 200})) {
  1255  		result = append(result, x)
  1256  	Y:
  1257  		// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
  1258  		for _, y := range Check2(VeryBadOfSliceIndex([]int{10, 20})) {
  1259  			result = append(result, y)
  1260  
  1261  			for k, z := range Check2(OfSliceIndex([]int{1, 2})) { // iterator does not panic
  1262  				result = append(result, z)
  1263  				if k == 1 {
  1264  					break Y
  1265  				}
  1266  			}
  1267  		}
  1268  	}
  1269  }
  1270  
  1271  func TestPanickyIterator4(t *testing.T) {
  1272  	var result []int
  1273  	var expect = []int{1, 2, 3}
  1274  	defer func() {
  1275  		if r := recover(); r != nil {
  1276  			if matchError(r, RERR_MISSING) {
  1277  				t.Logf("Saw expected panic '%v'", r)
  1278  			} else {
  1279  				t.Errorf("Saw wrong panic '%v'", r)
  1280  			}
  1281  		}
  1282  		if !slices.Equal(expect, result) {
  1283  			t.Errorf("Expected %v, got %v", expect, result)
  1284  		}
  1285  	}()
  1286  	for _, x := range SwallowPanicOfSliceIndex([]int{1, 2, 3, 4}) {
  1287  		result = append(result, x)
  1288  		if x == 3 {
  1289  			panic("x is 3")
  1290  		}
  1291  	}
  1292  
  1293  }
  1294  func TestPanickyIterator4Check(t *testing.T) {
  1295  	var result []int
  1296  	var expect = []int{1, 2, 3}
  1297  	defer func() {
  1298  		if r := recover(); r != nil {
  1299  			if matchError(r, CERR_MISSING) {
  1300  				t.Logf("Saw expected panic '%v'", r)
  1301  			} else {
  1302  				t.Errorf("Saw wrong panic '%v'", r)
  1303  			}
  1304  		}
  1305  		if !slices.Equal(expect, result) {
  1306  			t.Errorf("Expected %v, got %v", expect, result)
  1307  		}
  1308  	}()
  1309  	for _, x := range Check2(SwallowPanicOfSliceIndex([]int{1, 2, 3, 4})) {
  1310  		result = append(result, x)
  1311  		if x == 3 {
  1312  			panic("x is 3")
  1313  		}
  1314  	}
  1315  
  1316  }
  1317  
  1318  // veryBad tests that a loop nest behaves sensibly in the face of a
  1319  // "very bad" iterator.  In this case, "sensibly" means that the
  1320  // break out of X still occurs after the very bad iterator finally
  1321  // quits running (the control flow bread crumbs remain.)
  1322  func veryBad(s []int) []int {
  1323  	var result []int
  1324  X:
  1325  	for _, x := range OfSliceIndex([]int{1, 2, 3}) {
  1326  
  1327  		result = append(result, x)
  1328  
  1329  		for _, y := range VeryBadOfSliceIndex(s) {
  1330  			result = append(result, y)
  1331  			break X
  1332  		}
  1333  		for _, z := range OfSliceIndex([]int{100, 200, 300}) {
  1334  			result = append(result, z)
  1335  			if z == 100 {
  1336  				break
  1337  			}
  1338  		}
  1339  	}
  1340  	return result
  1341  }
  1342  
  1343  // veryBadCheck wraps a "very bad" iterator with Check,
  1344  // demonstrating that the very bad iterator also hides panics
  1345  // thrown by Check.
  1346  func veryBadCheck(s []int) []int {
  1347  	var result []int
  1348  X:
  1349  	for _, x := range OfSliceIndex([]int{1, 2, 3}) {
  1350  
  1351  		result = append(result, x)
  1352  
  1353  		for _, y := range Check2(VeryBadOfSliceIndex(s)) {
  1354  			result = append(result, y)
  1355  			break X
  1356  		}
  1357  		for _, z := range OfSliceIndex([]int{100, 200, 300}) {
  1358  			result = append(result, z)
  1359  			if z == 100 {
  1360  				break
  1361  			}
  1362  		}
  1363  	}
  1364  	return result
  1365  }
  1366  
  1367  // okay is the not-bad version of veryBad.
  1368  // They should behave the same.
  1369  func okay(s []int) []int {
  1370  	var result []int
  1371  X:
  1372  	for _, x := range OfSliceIndex([]int{1, 2, 3}) {
  1373  
  1374  		result = append(result, x)
  1375  
  1376  		for _, y := range OfSliceIndex(s) {
  1377  			result = append(result, y)
  1378  			break X
  1379  		}
  1380  		for _, z := range OfSliceIndex([]int{100, 200, 300}) {
  1381  			result = append(result, z)
  1382  			if z == 100 {
  1383  				break
  1384  			}
  1385  		}
  1386  	}
  1387  	return result
  1388  }
  1389  
  1390  // TestVeryBad1 checks the behavior of an extremely poorly behaved iterator.
  1391  func TestVeryBad1(t *testing.T) {
  1392  	result := veryBad([]int{10, 20, 30, 40, 50}) // odd length
  1393  	expect := []int{1, 10}
  1394  
  1395  	if !slices.Equal(expect, result) {
  1396  		t.Errorf("Expected %v, got %v", expect, result)
  1397  	}
  1398  }
  1399  
  1400  // TestVeryBad2 checks the behavior of an extremely poorly behaved iterator.
  1401  func TestVeryBad2(t *testing.T) {
  1402  	result := veryBad([]int{10, 20, 30, 40}) // even length
  1403  	expect := []int{1, 10}
  1404  
  1405  	if !slices.Equal(expect, result) {
  1406  		t.Errorf("Expected %v, got %v", expect, result)
  1407  	}
  1408  }
  1409  
  1410  // TestVeryBadCheck checks the behavior of an extremely poorly behaved iterator,
  1411  // which also suppresses the exceptions from "Check"
  1412  func TestVeryBadCheck(t *testing.T) {
  1413  	result := veryBadCheck([]int{10, 20, 30, 40}) // even length
  1414  	expect := []int{1, 10}
  1415  
  1416  	if !slices.Equal(expect, result) {
  1417  		t.Errorf("Expected %v, got %v", expect, result)
  1418  	}
  1419  }
  1420  
  1421  // TestOk is the nice version of the very bad iterator.
  1422  func TestOk(t *testing.T) {
  1423  	result := okay([]int{10, 20, 30, 40, 50}) // odd length
  1424  	expect := []int{1, 10}
  1425  
  1426  	if !slices.Equal(expect, result) {
  1427  		t.Errorf("Expected %v, got %v", expect, result)
  1428  	}
  1429  }
  1430  
  1431  // testBreak1BadDefer checks that defer behaves properly even in
  1432  // the presence of loop bodies panicking out of bad iterators.
  1433  // (i.e., the instrumentation did not break defer in these loops)
  1434  func testBreak1BadDefer(t *testing.T) (result []int) {
  1435  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3, -30, -20, -10}
  1436  
  1437  	defer func() {
  1438  		if r := recover(); r != nil {
  1439  			if matchError(r, RERR_DONE) {
  1440  				t.Logf("Saw expected panic '%v'", r)
  1441  			} else {
  1442  				t.Errorf("Saw wrong panic '%v'", r)
  1443  			}
  1444  			if !slices.Equal(expect, result) {
  1445  				t.Errorf("(Inner) Expected %v, got %v", expect, result)
  1446  			}
  1447  		} else {
  1448  			t.Error("Wanted to see a failure")
  1449  		}
  1450  	}()
  1451  
  1452  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1453  		if x == -4 {
  1454  			break
  1455  		}
  1456  		defer func() {
  1457  			result = append(result, x*10)
  1458  		}()
  1459  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1460  			if y == 3 {
  1461  				break
  1462  			}
  1463  			result = append(result, y)
  1464  		}
  1465  		result = append(result, x)
  1466  	}
  1467  	return
  1468  }
  1469  
  1470  func TestBreak1BadDefer(t *testing.T) {
  1471  	var result []int
  1472  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3, -30, -20, -10}
  1473  	result = testBreak1BadDefer(t)
  1474  	if !slices.Equal(expect, result) {
  1475  		t.Errorf("(Outer) Expected %v, got %v", expect, result)
  1476  	}
  1477  }
  1478  
  1479  // testReturn1 has no bad iterators.
  1480  func testReturn1(t *testing.T) (result []int, err any) {
  1481  	defer func() {
  1482  		err = recover()
  1483  	}()
  1484  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1485  		result = append(result, x)
  1486  		if x == -4 {
  1487  			break
  1488  		}
  1489  		defer func() {
  1490  			result = append(result, x*10)
  1491  		}()
  1492  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1493  			if y == 3 {
  1494  				return
  1495  			}
  1496  			result = append(result, y)
  1497  		}
  1498  		result = append(result, x)
  1499  	}
  1500  	return
  1501  }
  1502  
  1503  // testReturn2 has an outermost bad iterator
  1504  func testReturn2(t *testing.T) (result []int, err any) {
  1505  	defer func() {
  1506  		err = recover()
  1507  	}()
  1508  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1509  		result = append(result, x)
  1510  		if x == -4 {
  1511  			break
  1512  		}
  1513  		defer func() {
  1514  			result = append(result, x*10)
  1515  		}()
  1516  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1517  			if y == 3 {
  1518  				return
  1519  			}
  1520  			result = append(result, y)
  1521  		}
  1522  		result = append(result, x)
  1523  	}
  1524  	return
  1525  }
  1526  
  1527  // testReturn3 has an innermost bad iterator
  1528  func testReturn3(t *testing.T) (result []int, err any) {
  1529  	defer func() {
  1530  		err = recover()
  1531  	}()
  1532  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1533  		result = append(result, x)
  1534  		if x == -4 {
  1535  			break
  1536  		}
  1537  		defer func() {
  1538  			result = append(result, x*10)
  1539  		}()
  1540  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1541  			if y == 3 {
  1542  				return
  1543  			}
  1544  			result = append(result, y)
  1545  		}
  1546  	}
  1547  	return
  1548  }
  1549  
  1550  // testReturn4 has no bad iterators, but exercises  return variable rewriting
  1551  // differs from testReturn1 because deferred append to "result" does not change
  1552  // the return value in this case.
  1553  func testReturn4(t *testing.T) (_ []int, _ []int, err any) {
  1554  	var result []int
  1555  	defer func() {
  1556  		err = recover()
  1557  	}()
  1558  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1559  		result = append(result, x)
  1560  		if x == -4 {
  1561  			break
  1562  		}
  1563  		defer func() {
  1564  			result = append(result, x*10)
  1565  		}()
  1566  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1567  			if y == 3 {
  1568  				return result, result, nil
  1569  			}
  1570  			result = append(result, y)
  1571  		}
  1572  		result = append(result, x)
  1573  	}
  1574  	return
  1575  }
  1576  
  1577  // TestReturns checks that returns through bad iterators behave properly,
  1578  // for inner and outer bad iterators.
  1579  func TestReturns(t *testing.T) {
  1580  	var result []int
  1581  	var result2 []int
  1582  	var expect = []int{-1, 1, 2, -10}
  1583  	var expect2 = []int{-1, 1, 2}
  1584  	var err any
  1585  
  1586  	result, err = testReturn1(t)
  1587  	if !slices.Equal(expect, result) {
  1588  		t.Errorf("Expected %v, got %v", expect, result)
  1589  	}
  1590  	if err != nil {
  1591  		t.Errorf("Unexpected error %v", err)
  1592  	}
  1593  
  1594  	result, err = testReturn2(t)
  1595  	if !slices.Equal(expect, result) {
  1596  		t.Errorf("Expected %v, got %v", expect, result)
  1597  	}
  1598  	if err == nil {
  1599  		t.Errorf("Missing expected error")
  1600  	} else {
  1601  		if matchError(err, RERR_DONE) {
  1602  			t.Logf("Saw expected panic '%v'", err)
  1603  		} else {
  1604  			t.Errorf("Saw wrong panic '%v'", err)
  1605  		}
  1606  	}
  1607  
  1608  	result, err = testReturn3(t)
  1609  	if !slices.Equal(expect, result) {
  1610  		t.Errorf("Expected %v, got %v", expect, result)
  1611  	}
  1612  	if err == nil {
  1613  		t.Errorf("Missing expected error")
  1614  	} else {
  1615  		if matchError(err, RERR_DONE) {
  1616  			t.Logf("Saw expected panic '%v'", err)
  1617  		} else {
  1618  			t.Errorf("Saw wrong panic '%v'", err)
  1619  		}
  1620  	}
  1621  
  1622  	result, result2, err = testReturn4(t)
  1623  	if !slices.Equal(expect2, result) {
  1624  		t.Errorf("Expected %v, got %v", expect2, result)
  1625  	}
  1626  	if !slices.Equal(expect2, result2) {
  1627  		t.Errorf("Expected %v, got %v", expect2, result2)
  1628  	}
  1629  	if err != nil {
  1630  		t.Errorf("Unexpected error %v", err)
  1631  	}
  1632  }
  1633  
  1634  // testGotoA1 tests loop-nest-internal goto, no bad iterators.
  1635  func testGotoA1(t *testing.T) (result []int, err any) {
  1636  	defer func() {
  1637  		err = recover()
  1638  	}()
  1639  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1640  		result = append(result, x)
  1641  		if x == -4 {
  1642  			break
  1643  		}
  1644  		defer func() {
  1645  			result = append(result, x*10)
  1646  		}()
  1647  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1648  			if y == 3 {
  1649  				goto A
  1650  			}
  1651  			result = append(result, y)
  1652  		}
  1653  		result = append(result, x)
  1654  	A:
  1655  	}
  1656  	return
  1657  }
  1658  
  1659  // testGotoA2 tests loop-nest-internal goto, outer bad iterator.
  1660  func testGotoA2(t *testing.T) (result []int, err any) {
  1661  	defer func() {
  1662  		err = recover()
  1663  	}()
  1664  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1665  		result = append(result, x)
  1666  		if x == -4 {
  1667  			break
  1668  		}
  1669  		defer func() {
  1670  			result = append(result, x*10)
  1671  		}()
  1672  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1673  			if y == 3 {
  1674  				goto A
  1675  			}
  1676  			result = append(result, y)
  1677  		}
  1678  		result = append(result, x)
  1679  	A:
  1680  	}
  1681  	return
  1682  }
  1683  
  1684  // testGotoA3 tests loop-nest-internal goto, inner bad iterator.
  1685  func testGotoA3(t *testing.T) (result []int, err any) {
  1686  	defer func() {
  1687  		err = recover()
  1688  	}()
  1689  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1690  		result = append(result, x)
  1691  		if x == -4 {
  1692  			break
  1693  		}
  1694  		defer func() {
  1695  			result = append(result, x*10)
  1696  		}()
  1697  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1698  			if y == 3 {
  1699  				goto A
  1700  			}
  1701  			result = append(result, y)
  1702  		}
  1703  		result = append(result, x)
  1704  	A:
  1705  	}
  1706  	return
  1707  }
  1708  
  1709  func TestGotoA(t *testing.T) {
  1710  	var result []int
  1711  	var expect = []int{-1, 1, 2, -2, 1, 2, -3, 1, 2, -4, -30, -20, -10}
  1712  	var expect3 = []int{-1, 1, 2, -10} // first goto becomes a panic
  1713  	var err any
  1714  
  1715  	result, err = testGotoA1(t)
  1716  	if !slices.Equal(expect, result) {
  1717  		t.Errorf("Expected %v, got %v", expect, result)
  1718  	}
  1719  	if err != nil {
  1720  		t.Errorf("Unexpected error %v", err)
  1721  	}
  1722  
  1723  	result, err = testGotoA2(t)
  1724  	if !slices.Equal(expect, result) {
  1725  		t.Errorf("Expected %v, got %v", expect, result)
  1726  	}
  1727  	if err == nil {
  1728  		t.Errorf("Missing expected error")
  1729  	} else {
  1730  		if matchError(err, RERR_DONE) {
  1731  			t.Logf("Saw expected panic '%v'", err)
  1732  		} else {
  1733  			t.Errorf("Saw wrong panic '%v'", err)
  1734  		}
  1735  	}
  1736  
  1737  	result, err = testGotoA3(t)
  1738  	if !slices.Equal(expect3, result) {
  1739  		t.Errorf("Expected %v, got %v", expect3, result)
  1740  	}
  1741  	if err == nil {
  1742  		t.Errorf("Missing expected error")
  1743  	} else {
  1744  		if matchError(err, RERR_DONE) {
  1745  			t.Logf("Saw expected panic '%v'", err)
  1746  		} else {
  1747  			t.Errorf("Saw wrong panic '%v'", err)
  1748  		}
  1749  	}
  1750  }
  1751  
  1752  // testGotoB1 tests loop-nest-exiting goto, no bad iterators.
  1753  func testGotoB1(t *testing.T) (result []int, err any) {
  1754  	defer func() {
  1755  		err = recover()
  1756  	}()
  1757  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1758  		result = append(result, x)
  1759  		if x == -4 {
  1760  			break
  1761  		}
  1762  		defer func() {
  1763  			result = append(result, x*10)
  1764  		}()
  1765  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1766  			if y == 3 {
  1767  				goto B
  1768  			}
  1769  			result = append(result, y)
  1770  		}
  1771  		result = append(result, x)
  1772  	}
  1773  B:
  1774  	result = append(result, 999)
  1775  	return
  1776  }
  1777  
  1778  // testGotoB2 tests loop-nest-exiting goto, outer bad iterator.
  1779  func testGotoB2(t *testing.T) (result []int, err any) {
  1780  	defer func() {
  1781  		err = recover()
  1782  	}()
  1783  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1784  		result = append(result, x)
  1785  		if x == -4 {
  1786  			break
  1787  		}
  1788  		defer func() {
  1789  			result = append(result, x*10)
  1790  		}()
  1791  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1792  			if y == 3 {
  1793  				goto B
  1794  			}
  1795  			result = append(result, y)
  1796  		}
  1797  		result = append(result, x)
  1798  	}
  1799  B:
  1800  	result = append(result, 999)
  1801  	return
  1802  }
  1803  
  1804  // testGotoB3 tests loop-nest-exiting goto, inner bad iterator.
  1805  func testGotoB3(t *testing.T) (result []int, err any) {
  1806  	defer func() {
  1807  		err = recover()
  1808  	}()
  1809  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1810  		result = append(result, x)
  1811  		if x == -4 {
  1812  			break
  1813  		}
  1814  		defer func() {
  1815  			result = append(result, x*10)
  1816  		}()
  1817  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1818  			if y == 3 {
  1819  				goto B
  1820  			}
  1821  			result = append(result, y)
  1822  		}
  1823  		result = append(result, x)
  1824  	}
  1825  B:
  1826  	result = append(result, 999)
  1827  	return
  1828  }
  1829  
  1830  func TestGotoB(t *testing.T) {
  1831  	var result []int
  1832  	var expect = []int{-1, 1, 2, 999, -10}
  1833  	var expectX = []int{-1, 1, 2, -10}
  1834  	var err any
  1835  
  1836  	result, err = testGotoB1(t)
  1837  	if !slices.Equal(expect, result) {
  1838  		t.Errorf("Expected %v, got %v", expect, result)
  1839  	}
  1840  	if err != nil {
  1841  		t.Errorf("Unexpected error %v", err)
  1842  	}
  1843  
  1844  	result, err = testGotoB2(t)
  1845  	if !slices.Equal(expectX, result) {
  1846  		t.Errorf("Expected %v, got %v", expectX, result)
  1847  	}
  1848  	if err == nil {
  1849  		t.Errorf("Missing expected error")
  1850  	} else {
  1851  		if matchError(err, RERR_DONE) {
  1852  			t.Logf("Saw expected panic '%v'", err)
  1853  		} else {
  1854  			t.Errorf("Saw wrong panic '%v'", err)
  1855  		}
  1856  	}
  1857  
  1858  	result, err = testGotoB3(t)
  1859  	if !slices.Equal(expectX, result) {
  1860  		t.Errorf("Expected %v, got %v", expectX, result)
  1861  	}
  1862  	if err == nil {
  1863  		t.Errorf("Missing expected error")
  1864  	} else {
  1865  		matchErrorHelper(t, err, RERR_DONE)
  1866  	}
  1867  }
  1868  
  1869  // once returns an iterator that runs its loop body once with the supplied value
  1870  func once[T any](x T) Seq[T] {
  1871  	return func(yield func(T) bool) {
  1872  		yield(x)
  1873  	}
  1874  }
  1875  
  1876  // terrify converts an iterator into one that panics with the supplied string
  1877  // if/when the loop body terminates early (returns false, for break, goto, outer
  1878  // continue, or return).
  1879  func terrify[T any](s string, forall Seq[T]) Seq[T] {
  1880  	return func(yield func(T) bool) {
  1881  		forall(func(v T) bool {
  1882  			if !yield(v) {
  1883  				panic(s)
  1884  			}
  1885  			return true
  1886  		})
  1887  	}
  1888  }
  1889  
  1890  func use[T any](T) {
  1891  }
  1892  
  1893  // f runs a not-rangefunc iterator that recovers from a panic that follows execution of a return.
  1894  // what does f return?
  1895  func f() string {
  1896  	defer func() { recover() }()
  1897  	defer panic("f panic")
  1898  	for _, s := range []string{"f return"} {
  1899  		return s
  1900  	}
  1901  	return "f not reached"
  1902  }
  1903  
  1904  // g runs a rangefunc iterator that recovers from a panic that follows execution of a return.
  1905  // what does g return?
  1906  func g() string {
  1907  	defer func() { recover() }()
  1908  	for s := range terrify("g panic", once("g return")) {
  1909  		return s
  1910  	}
  1911  	return "g not reached"
  1912  }
  1913  
  1914  // h runs a rangefunc iterator that recovers from a panic that follows execution of a return.
  1915  // the panic occurs in the rangefunc iterator itself.
  1916  // what does h return?
  1917  func h() (hashS string) {
  1918  	defer func() { recover() }()
  1919  	for s := range terrify("h panic", once("h return")) {
  1920  		hashS := s
  1921  		use(hashS)
  1922  		return s
  1923  	}
  1924  	return "h not reached"
  1925  }
  1926  
  1927  func j() (hashS string) {
  1928  	defer func() { recover() }()
  1929  	for s := range terrify("j panic", once("j return")) {
  1930  		hashS = s
  1931  		return
  1932  	}
  1933  	return "j not reached"
  1934  }
  1935  
  1936  // k runs a rangefunc iterator that recovers from a panic that follows execution of a return.
  1937  // the panic occurs in the rangefunc iterator itself.
  1938  // k includes an additional mechanism to for making the return happen
  1939  // what does k return?
  1940  func k() (hashS string) {
  1941  	_return := func(s string) { hashS = s }
  1942  
  1943  	defer func() { recover() }()
  1944  	for s := range terrify("k panic", once("k return")) {
  1945  		_return(s)
  1946  		return
  1947  	}
  1948  	return "k not reached"
  1949  }
  1950  
  1951  func m() (hashS string) {
  1952  	_return := func(s string) { hashS = s }
  1953  
  1954  	defer func() { recover() }()
  1955  	for s := range terrify("m panic", once("m return")) {
  1956  		defer _return(s)
  1957  		return s + ", but should be replaced in a defer"
  1958  	}
  1959  	return "m not reached"
  1960  }
  1961  
  1962  func n() string {
  1963  	defer func() { recover() }()
  1964  	for s := range terrify("n panic", once("n return")) {
  1965  		return s + func(s string) string {
  1966  			defer func() { recover() }()
  1967  			for s := range terrify("n closure panic", once(s)) {
  1968  				return s
  1969  			}
  1970  			return "n closure not reached"
  1971  		}(" and n closure return")
  1972  	}
  1973  	return "n not reached"
  1974  }
  1975  
  1976  type terrifyTestCase struct {
  1977  	f func() string
  1978  	e string
  1979  }
  1980  
  1981  func TestPanicReturns(t *testing.T) {
  1982  	tcs := []terrifyTestCase{
  1983  		{f, "f return"},
  1984  		{g, "g return"},
  1985  		{h, "h return"},
  1986  		{k, "k return"},
  1987  		{j, "j return"},
  1988  		{m, "m return"},
  1989  		{n, "n return and n closure return"},
  1990  	}
  1991  
  1992  	for _, tc := range tcs {
  1993  		got := tc.f()
  1994  		if got != tc.e {
  1995  			t.Errorf("Got %s expected %s", got, tc.e)
  1996  		} else {
  1997  			t.Logf("Got expected %s", got)
  1998  		}
  1999  	}
  2000  }
  2001  
  2002  // twice calls yield twice, the first time defer-recover-saving any panic,
  2003  // for re-panicking later if the second call to yield does not also panic.
  2004  // If the first call panicked, the second call ought to also panic because
  2005  // it was called after a panic-termination of the loop body.
  2006  func twice[T any](x, y T) Seq[T] {
  2007  	return func(yield func(T) bool) {
  2008  		var p any
  2009  		done := false
  2010  		func() {
  2011  			defer func() {
  2012  				p = recover()
  2013  			}()
  2014  			done = !yield(x)
  2015  		}()
  2016  		if done {
  2017  			return
  2018  		}
  2019  		yield(y)
  2020  		if p != nil {
  2021  			// do not swallow the panic
  2022  			panic(p)
  2023  		}
  2024  	}
  2025  }
  2026  
  2027  func TestRunBodyAfterPanic(t *testing.T) {
  2028  	defer func() {
  2029  		if r := recover(); r != nil {
  2030  			if matchError(r, RERR_PANIC) {
  2031  				t.Logf("Saw expected panic '%v'", r)
  2032  			} else {
  2033  				t.Errorf("Saw wrong panic '%v'", r)
  2034  			}
  2035  		} else {
  2036  			t.Errorf("Wanted to see a failure, result")
  2037  		}
  2038  	}()
  2039  	for x := range twice(0, 1) {
  2040  		if x == 0 {
  2041  			panic("x is zero")
  2042  		}
  2043  	}
  2044  }
  2045  
  2046  func TestRunBodyAfterPanicCheck(t *testing.T) {
  2047  	defer func() {
  2048  		if r := recover(); r != nil {
  2049  			if matchError(r, CERR_PANIC) {
  2050  				t.Logf("Saw expected panic '%v'", r)
  2051  			} else {
  2052  				t.Errorf("Saw wrong panic '%v'", r)
  2053  			}
  2054  		} else {
  2055  			t.Errorf("Wanted to see a failure, result")
  2056  		}
  2057  	}()
  2058  	for x := range Check(twice(0, 1)) {
  2059  		if x == 0 {
  2060  			panic("x is zero")
  2061  		}
  2062  	}
  2063  }
  2064  
  2065  func TestTwoLevelReturn(t *testing.T) {
  2066  	f := func() int {
  2067  		for a := range twice(0, 1) {
  2068  			for b := range twice(0, 2) {
  2069  				x := a + b
  2070  				t.Logf("x=%d", x)
  2071  				if x == 3 {
  2072  					return x
  2073  				}
  2074  			}
  2075  		}
  2076  		return -1
  2077  	}
  2078  	y := f()
  2079  	if y != 3 {
  2080  		t.Errorf("Expected y=3, got y=%d\n", y)
  2081  	}
  2082  }
  2083  
  2084  func TestTwoLevelReturnCheck(t *testing.T) {
  2085  	f := func() int {
  2086  		for a := range Check(twice(0, 1)) {
  2087  			for b := range Check(twice(0, 2)) {
  2088  				x := a + b
  2089  				t.Logf("a=%d, b=%d, x=%d", a, b, x)
  2090  				if x == 3 {
  2091  					return x
  2092  				}
  2093  			}
  2094  		}
  2095  		return -1
  2096  	}
  2097  	y := f()
  2098  	if y != 3 {
  2099  		t.Errorf("Expected y=3, got y=%d\n", y)
  2100  	}
  2101  }
  2102  

View as plain text