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

View as plain text