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  //go:build goexperiment.rangefunc
     6  
     7  package rangefunc_test
     8  
     9  import (
    10  	"slices"
    11  	"testing"
    12  )
    13  
    14  type Seq2[T1, T2 any] func(yield func(T1, T2) bool)
    15  
    16  // OfSliceIndex returns a Seq over the elements of s. It is equivalent
    17  // to range s.
    18  func OfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    19  	return func(yield func(int, T) bool) {
    20  		for i, v := range s {
    21  			if !yield(i, v) {
    22  				return
    23  			}
    24  		}
    25  		return
    26  	}
    27  }
    28  
    29  // BadOfSliceIndex is "bad" because it ignores the return value from yield
    30  // and just keeps on iterating.
    31  func BadOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    32  	return func(yield func(int, T) bool) {
    33  		for i, v := range s {
    34  			yield(i, v)
    35  		}
    36  		return
    37  	}
    38  }
    39  
    40  // VeryBadOfSliceIndex is "very bad" because it ignores the return value from yield
    41  // and just keeps on iterating, and also wraps that call in a defer-recover so it can
    42  // keep on trying after the first panic.
    43  func VeryBadOfSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
    44  	return func(yield func(int, T) bool) {
    45  		for i, v := range s {
    46  			func() {
    47  				defer func() {
    48  					recover()
    49  				}()
    50  				yield(i, v)
    51  			}()
    52  		}
    53  		return
    54  	}
    55  }
    56  
    57  // CooperativeBadOfSliceIndex calls the loop body from a goroutine after
    58  // a ping on a channel, and returns recover()on that same channel.
    59  func CooperativeBadOfSliceIndex[T any, S ~[]T](s S, proceed chan any) Seq2[int, T] {
    60  	return func(yield func(int, T) bool) {
    61  		for i, v := range s {
    62  			if !yield(i, v) {
    63  				// if the body breaks, call yield just once in a goroutine
    64  				go func() {
    65  					<-proceed
    66  					defer func() {
    67  						proceed <- recover()
    68  					}()
    69  					yield(0, s[0])
    70  				}()
    71  				return
    72  			}
    73  		}
    74  		return
    75  	}
    76  }
    77  
    78  // TrickyIterator is a type intended to test whether an iterator that
    79  // calls a yield function after loop exit must inevitably escape the
    80  // closure; this might be relevant to future checking/optimization.
    81  type TrickyIterator struct {
    82  	yield func(int, int) bool
    83  }
    84  
    85  func (ti *TrickyIterator) iterAll(s []int) Seq2[int, int] {
    86  	return func(yield func(int, int) bool) {
    87  		ti.yield = yield // Save yield for future abuse
    88  		for i, v := range s {
    89  			if !yield(i, v) {
    90  				return
    91  			}
    92  		}
    93  		return
    94  	}
    95  }
    96  
    97  func (ti *TrickyIterator) iterOne(s []int) Seq2[int, int] {
    98  	return func(yield func(int, int) bool) {
    99  		ti.yield = yield // Save yield for future abuse
   100  		if len(s) > 0 {  // Not in a loop might escape differently
   101  			yield(0, s[0])
   102  		}
   103  		return
   104  	}
   105  }
   106  
   107  func (ti *TrickyIterator) iterZero(s []int) Seq2[int, int] {
   108  	return func(yield func(int, int) bool) {
   109  		ti.yield = yield // Save yield for future abuse
   110  		// Don't call it at all, maybe it won't escape
   111  		return
   112  	}
   113  }
   114  
   115  func (ti *TrickyIterator) fail() {
   116  	if ti.yield != nil {
   117  		ti.yield(1, 1)
   118  	}
   119  }
   120  
   121  // Check wraps the function body passed to iterator forall
   122  // in code that ensures that it cannot (successfully) be called
   123  // either after body return false (control flow out of loop) or
   124  // forall itself returns (the iteration is now done).
   125  //
   126  // Note that this can catch errors before the inserted checks.
   127  func Check[U, V any](forall Seq2[U, V]) Seq2[U, V] {
   128  	return func(body func(U, V) bool) {
   129  		ret := true
   130  		forall(func(u U, v V) bool {
   131  			if !ret {
   132  				panic("Checked iterator access after exit")
   133  			}
   134  			ret = body(u, v)
   135  			return ret
   136  		})
   137  		ret = false
   138  	}
   139  }
   140  
   141  func TestCheck(t *testing.T) {
   142  	i := 0
   143  	defer func() {
   144  		if r := recover(); r != nil {
   145  			t.Logf("Saw expected panic '%v'", r)
   146  		} else {
   147  			t.Error("Wanted to see a failure")
   148  		}
   149  	}()
   150  	for _, x := range Check(BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) {
   151  		i += x
   152  		if i > 4*9 {
   153  			break
   154  		}
   155  	}
   156  }
   157  
   158  func TestCooperativeBadOfSliceIndex(t *testing.T) {
   159  	i := 0
   160  	proceed := make(chan any)
   161  	for _, x := range CooperativeBadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, proceed) {
   162  		i += x
   163  		if i >= 36 {
   164  			break
   165  		}
   166  	}
   167  	proceed <- true
   168  	if r := <-proceed; r != nil {
   169  		t.Logf("Saw expected panic '%v'", r)
   170  	} else {
   171  		t.Error("Wanted to see a failure")
   172  	}
   173  	if i != 36 {
   174  		t.Errorf("Expected i == 36, saw %d instead", i)
   175  	} else {
   176  		t.Logf("i = %d", i)
   177  	}
   178  }
   179  
   180  func TestCheckCooperativeBadOfSliceIndex(t *testing.T) {
   181  	i := 0
   182  	proceed := make(chan any)
   183  	for _, x := range Check(CooperativeBadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, proceed)) {
   184  		i += x
   185  		if i >= 36 {
   186  			break
   187  		}
   188  	}
   189  	proceed <- true
   190  	if r := <-proceed; r != nil {
   191  		t.Logf("Saw expected panic '%v'", r)
   192  	} else {
   193  		t.Error("Wanted to see a failure")
   194  	}
   195  	if i != 36 {
   196  		t.Errorf("Expected i == 36, saw %d instead", i)
   197  	} else {
   198  		t.Logf("i = %d", i)
   199  	}
   200  }
   201  
   202  func TestTrickyIterAll(t *testing.T) {
   203  	trickItAll := TrickyIterator{}
   204  	i := 0
   205  	for _, x := range trickItAll.iterAll([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   206  		i += x
   207  		if i >= 36 {
   208  			break
   209  		}
   210  	}
   211  
   212  	if i != 36 {
   213  		t.Errorf("Expected i == 36, saw %d instead", i)
   214  	} else {
   215  		t.Logf("i = %d", i)
   216  	}
   217  
   218  	defer func() {
   219  		if r := recover(); r != nil {
   220  			t.Logf("Saw expected panic '%v'", r)
   221  		} else {
   222  			t.Error("Wanted to see a failure")
   223  		}
   224  	}()
   225  
   226  	trickItAll.fail()
   227  }
   228  
   229  func TestTrickyIterOne(t *testing.T) {
   230  	trickItOne := TrickyIterator{}
   231  	i := 0
   232  	for _, x := range trickItOne.iterOne([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   233  		i += x
   234  		if i >= 36 {
   235  			break
   236  		}
   237  	}
   238  
   239  	// Don't care about value, ought to be 36 anyhow.
   240  	t.Logf("i = %d", i)
   241  
   242  	defer func() {
   243  		if r := recover(); r != nil {
   244  			t.Logf("Saw expected panic '%v'", r)
   245  		} else {
   246  			t.Error("Wanted to see a failure")
   247  		}
   248  	}()
   249  
   250  	trickItOne.fail()
   251  }
   252  
   253  func TestTrickyIterZero(t *testing.T) {
   254  	trickItZero := TrickyIterator{}
   255  	i := 0
   256  	for _, x := range trickItZero.iterZero([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   257  		i += x
   258  		if i >= 36 {
   259  			break
   260  		}
   261  	}
   262  
   263  	// Don't care about value, ought to be 0 anyhow.
   264  	t.Logf("i = %d", i)
   265  
   266  	defer func() {
   267  		if r := recover(); r != nil {
   268  			t.Logf("Saw expected panic '%v'", r)
   269  		} else {
   270  			t.Error("Wanted to see a failure")
   271  		}
   272  	}()
   273  
   274  	trickItZero.fail()
   275  }
   276  
   277  func TestCheckTrickyIterZero(t *testing.T) {
   278  	trickItZero := TrickyIterator{}
   279  	i := 0
   280  	for _, x := range Check(trickItZero.iterZero([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) {
   281  		i += x
   282  		if i >= 36 {
   283  			break
   284  		}
   285  	}
   286  
   287  	// Don't care about value, ought to be 0 anyhow.
   288  	t.Logf("i = %d", i)
   289  
   290  	defer func() {
   291  		if r := recover(); r != nil {
   292  			t.Logf("Saw expected panic '%v'", r)
   293  		} else {
   294  			t.Error("Wanted to see a failure")
   295  		}
   296  	}()
   297  
   298  	trickItZero.fail()
   299  }
   300  
   301  // TestBreak1 should just work, with well-behaved iterators.
   302  // (The misbehaving iterator detector should not trigger.)
   303  func TestBreak1(t *testing.T) {
   304  	var result []int
   305  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3}
   306  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4}) {
   307  		if x == -4 {
   308  			break
   309  		}
   310  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   311  			if y == 3 {
   312  				break
   313  			}
   314  			result = append(result, y)
   315  		}
   316  		result = append(result, x)
   317  	}
   318  	if !slices.Equal(expect, result) {
   319  		t.Errorf("Expected %v, got %v", expect, result)
   320  	}
   321  }
   322  
   323  // TestBreak2 should just work, with well-behaved iterators.
   324  // (The misbehaving iterator detector should not trigger.)
   325  func TestBreak2(t *testing.T) {
   326  	var result []int
   327  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3}
   328  outer:
   329  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4}) {
   330  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   331  			if y == 3 {
   332  				break
   333  			}
   334  			if x == -4 {
   335  				break outer
   336  			}
   337  
   338  			result = append(result, y)
   339  		}
   340  		result = append(result, x)
   341  	}
   342  	if !slices.Equal(expect, result) {
   343  		t.Errorf("Expected %v, got %v", expect, result)
   344  	}
   345  }
   346  
   347  // TestContinue should just work, with well-behaved iterators.
   348  // (The misbehaving iterator detector should not trigger.)
   349  func TestContinue(t *testing.T) {
   350  	var result []int
   351  	var expect = []int{-1, 1, 2, -2, 1, 2, -3, 1, 2, -4}
   352  outer:
   353  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4}) {
   354  		result = append(result, x)
   355  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   356  			if y == 3 {
   357  				continue outer
   358  			}
   359  			if x == -4 {
   360  				break outer
   361  			}
   362  
   363  			result = append(result, y)
   364  		}
   365  		result = append(result, x-10)
   366  	}
   367  	if !slices.Equal(expect, result) {
   368  		t.Errorf("Expected %v, got %v", expect, result)
   369  	}
   370  }
   371  
   372  // TestBreak3 should just work, with well-behaved iterators.
   373  // (The misbehaving iterator detector should not trigger.)
   374  func TestBreak3(t *testing.T) {
   375  	var result []int
   376  	var expect = []int{100, 10, 2, 4, 200, 10, 2, 4, 20, 2, 4, 300, 10, 2, 4, 20, 2, 4, 30}
   377  X:
   378  	for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   379  	Y:
   380  		for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   381  			if 10*y >= x {
   382  				break
   383  			}
   384  			result = append(result, y)
   385  			if y == 30 {
   386  				continue X
   387  			}
   388  		Z:
   389  			for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   390  				if z&1 == 1 {
   391  					continue Z
   392  				}
   393  				result = append(result, z)
   394  				if z >= 4 {
   395  					continue Y
   396  				}
   397  			}
   398  			result = append(result, -y) // should never be executed
   399  		}
   400  		result = append(result, x)
   401  	}
   402  	if !slices.Equal(expect, result) {
   403  		t.Errorf("Expected %v, got %v", expect, result)
   404  	}
   405  }
   406  
   407  // TestBreak1BadA should end in a panic when the outer-loop's
   408  // single-level break is ignore by BadOfSliceIndex
   409  func TestBreak1BadA(t *testing.T) {
   410  	var result []int
   411  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3}
   412  
   413  	defer func() {
   414  		if r := recover(); r != nil {
   415  			t.Logf("Saw expected panic '%v'", r)
   416  			if !slices.Equal(expect, result) {
   417  				t.Errorf("Expected %v, got %v", expect, result)
   418  			}
   419  		} else {
   420  			t.Error("Wanted to see a failure")
   421  		}
   422  	}()
   423  
   424  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   425  		if x == -4 {
   426  			break
   427  		}
   428  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   429  			if y == 3 {
   430  				break
   431  			}
   432  			result = append(result, y)
   433  		}
   434  		result = append(result, x)
   435  	}
   436  }
   437  
   438  // TestBreak1BadB should end in a panic, sooner, when the inner-loop's
   439  // (nested) single-level break is ignored by BadOfSliceIndex
   440  func TestBreak1BadB(t *testing.T) {
   441  	var result []int
   442  	var expect = []int{1, 2} // inner breaks, panics, after before outer appends
   443  
   444  	defer func() {
   445  		if r := recover(); r != nil {
   446  			t.Logf("Saw expected panic '%v'", r)
   447  			if !slices.Equal(expect, result) {
   448  				t.Errorf("Expected %v, got %v", expect, result)
   449  			}
   450  		} else {
   451  			t.Error("Wanted to see a failure")
   452  		}
   453  	}()
   454  
   455  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   456  		if x == -4 {
   457  			break
   458  		}
   459  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   460  			if y == 3 {
   461  				break
   462  			}
   463  			result = append(result, y)
   464  		}
   465  		result = append(result, x)
   466  	}
   467  }
   468  
   469  // TestMultiCont0 tests multilevel continue with no bad iterators
   470  // (it should just work)
   471  func TestMultiCont0(t *testing.T) {
   472  	var result []int
   473  	var expect = []int{1000, 10, 2, 4, 2000}
   474  
   475  W:
   476  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   477  		result = append(result, w)
   478  		if w == 2000 {
   479  			break
   480  		}
   481  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   482  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   483  				result = append(result, y)
   484  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   485  					if z&1 == 1 {
   486  						continue
   487  					}
   488  					result = append(result, z)
   489  					if z >= 4 {
   490  						continue W // modified to be multilevel
   491  					}
   492  				}
   493  				result = append(result, -y) // should never be executed
   494  			}
   495  			result = append(result, x)
   496  		}
   497  	}
   498  	if !slices.Equal(expect, result) {
   499  		t.Errorf("Expected %v, got %v", expect, result)
   500  	}
   501  }
   502  
   503  // TestMultiCont1 tests multilevel continue with a bad iterator
   504  // in the outermost loop exited by the continue.
   505  func TestMultiCont1(t *testing.T) {
   506  	var result []int
   507  	var expect = []int{1000, 10, 2, 4}
   508  	defer func() {
   509  		if r := recover(); r != nil {
   510  			t.Logf("Saw expected panic '%v'", r)
   511  			if !slices.Equal(expect, result) {
   512  				t.Errorf("Expected %v, got %v", expect, result)
   513  			}
   514  		} else {
   515  			t.Errorf("Wanted to see a failure, result was %v", result)
   516  		}
   517  	}()
   518  
   519  W:
   520  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   521  		result = append(result, w)
   522  		if w == 2000 {
   523  			break
   524  		}
   525  		for _, x := range BadOfSliceIndex([]int{100, 200, 300, 400}) {
   526  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   527  				result = append(result, y)
   528  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   529  					if z&1 == 1 {
   530  						continue
   531  					}
   532  					result = append(result, z)
   533  					if z >= 4 {
   534  						continue W
   535  					}
   536  				}
   537  				result = append(result, -y) // should never be executed
   538  			}
   539  			result = append(result, x)
   540  		}
   541  	}
   542  	if !slices.Equal(expect, result) {
   543  		t.Errorf("Expected %v, got %v", expect, result)
   544  	}
   545  }
   546  
   547  // TestMultiCont2 tests multilevel continue with a bad iterator
   548  // in a middle loop exited by the continue.
   549  func TestMultiCont2(t *testing.T) {
   550  	var result []int
   551  	var expect = []int{1000, 10, 2, 4}
   552  	defer func() {
   553  		if r := recover(); r != nil {
   554  			t.Logf("Saw expected panic '%v'", r)
   555  			if !slices.Equal(expect, result) {
   556  				t.Errorf("Expected %v, got %v", expect, result)
   557  			}
   558  		} else {
   559  			t.Errorf("Wanted to see a failure, result was %v", result)
   560  		}
   561  	}()
   562  
   563  W:
   564  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   565  		result = append(result, w)
   566  		if w == 2000 {
   567  			break
   568  		}
   569  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   570  			for _, y := range BadOfSliceIndex([]int{10, 20, 30, 40}) {
   571  				result = append(result, y)
   572  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   573  					if z&1 == 1 {
   574  						continue
   575  					}
   576  					result = append(result, z)
   577  					if z >= 4 {
   578  						continue W
   579  					}
   580  				}
   581  				result = append(result, -y) // should never be executed
   582  			}
   583  			result = append(result, x)
   584  		}
   585  	}
   586  	if !slices.Equal(expect, result) {
   587  		t.Errorf("Expected %v, got %v", expect, result)
   588  	}
   589  }
   590  
   591  // TestMultiCont3 tests multilevel continue with a bad iterator
   592  // in the innermost loop exited by the continue.
   593  func TestMultiCont3(t *testing.T) {
   594  	var result []int
   595  	var expect = []int{1000, 10, 2, 4}
   596  	defer func() {
   597  		if r := recover(); r != nil {
   598  			t.Logf("Saw expected panic '%v'", r)
   599  			if !slices.Equal(expect, result) {
   600  				t.Errorf("Expected %v, got %v", expect, result)
   601  			}
   602  		} else {
   603  			t.Errorf("Wanted to see a failure, result was %v", result)
   604  		}
   605  	}()
   606  
   607  W:
   608  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   609  		result = append(result, w)
   610  		if w == 2000 {
   611  			break
   612  		}
   613  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   614  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   615  				result = append(result, y)
   616  				for _, z := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   617  					if z&1 == 1 {
   618  						continue
   619  					}
   620  					result = append(result, z)
   621  					if z >= 4 {
   622  						continue W
   623  					}
   624  				}
   625  				result = append(result, -y) // should never be executed
   626  			}
   627  			result = append(result, x)
   628  		}
   629  	}
   630  	if !slices.Equal(expect, result) {
   631  		t.Errorf("Expected %v, got %v", expect, result)
   632  	}
   633  }
   634  
   635  // TestMultiBreak0 tests multilevel break with a bad iterator
   636  // in the outermost loop exited by the break (the outermost loop).
   637  func TestMultiBreak0(t *testing.T) {
   638  	var result []int
   639  	var expect = []int{1000, 10, 2, 4}
   640  	defer func() {
   641  		if r := recover(); r != nil {
   642  			t.Logf("Saw expected panic '%v'", r)
   643  			if !slices.Equal(expect, result) {
   644  				t.Errorf("Expected %v, got %v", expect, result)
   645  			}
   646  		} else {
   647  			t.Errorf("Wanted to see a failure, result was %v", result)
   648  		}
   649  	}()
   650  
   651  W:
   652  	for _, w := range BadOfSliceIndex([]int{1000, 2000}) {
   653  		result = append(result, w)
   654  		if w == 2000 {
   655  			break
   656  		}
   657  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   658  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   659  				result = append(result, y)
   660  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   661  					if z&1 == 1 {
   662  						continue
   663  					}
   664  					result = append(result, z)
   665  					if z >= 4 {
   666  						break W
   667  					}
   668  				}
   669  				result = append(result, -y) // should never be executed
   670  			}
   671  			result = append(result, x)
   672  		}
   673  	}
   674  	if !slices.Equal(expect, result) {
   675  		t.Errorf("Expected %v, got %v", expect, result)
   676  	}
   677  }
   678  
   679  // TestMultiBreak1 tests multilevel break with a bad iterator
   680  // in an intermediate loop exited by the break.
   681  func TestMultiBreak1(t *testing.T) {
   682  	var result []int
   683  	var expect = []int{1000, 10, 2, 4}
   684  	defer func() {
   685  		if r := recover(); r != nil {
   686  			t.Logf("Saw expected panic '%v'", r)
   687  			if !slices.Equal(expect, result) {
   688  				t.Errorf("Expected %v, got %v", expect, result)
   689  			}
   690  		} else {
   691  			t.Errorf("Wanted to see a failure, result was %v", result)
   692  		}
   693  	}()
   694  
   695  W:
   696  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   697  		result = append(result, w)
   698  		if w == 2000 {
   699  			break
   700  		}
   701  		for _, x := range BadOfSliceIndex([]int{100, 200, 300, 400}) {
   702  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   703  				result = append(result, y)
   704  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   705  					if z&1 == 1 {
   706  						continue
   707  					}
   708  					result = append(result, z)
   709  					if z >= 4 {
   710  						break W
   711  					}
   712  				}
   713  				result = append(result, -y) // should never be executed
   714  			}
   715  			result = append(result, x)
   716  		}
   717  	}
   718  	if !slices.Equal(expect, result) {
   719  		t.Errorf("Expected %v, got %v", expect, result)
   720  	}
   721  }
   722  
   723  // TestMultiBreak2 tests multilevel break with two bad iterators
   724  // in intermediate loops exited by the break.
   725  func TestMultiBreak2(t *testing.T) {
   726  	var result []int
   727  	var expect = []int{1000, 10, 2, 4}
   728  	defer func() {
   729  		if r := recover(); r != nil {
   730  			t.Logf("Saw expected panic '%v'", r)
   731  			if !slices.Equal(expect, result) {
   732  				t.Errorf("Expected %v, got %v", expect, result)
   733  			}
   734  		} else {
   735  			t.Errorf("Wanted to see a failure, result was %v", result)
   736  		}
   737  	}()
   738  
   739  W:
   740  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   741  		result = append(result, w)
   742  		if w == 2000 {
   743  			break
   744  		}
   745  		for _, x := range BadOfSliceIndex([]int{100, 200, 300, 400}) {
   746  			for _, y := range BadOfSliceIndex([]int{10, 20, 30, 40}) {
   747  				result = append(result, y)
   748  				for _, z := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   749  					if z&1 == 1 {
   750  						continue
   751  					}
   752  					result = append(result, z)
   753  					if z >= 4 {
   754  						break W
   755  					}
   756  				}
   757  				result = append(result, -y) // should never be executed
   758  			}
   759  			result = append(result, x)
   760  		}
   761  	}
   762  	if !slices.Equal(expect, result) {
   763  		t.Errorf("Expected %v, got %v", expect, result)
   764  	}
   765  }
   766  
   767  // TestMultiBreak3 tests multilevel break with the bad iterator
   768  // in the innermost loop exited by the break.
   769  func TestMultiBreak3(t *testing.T) {
   770  	var result []int
   771  	var expect = []int{1000, 10, 2, 4}
   772  	defer func() {
   773  		if r := recover(); r != nil {
   774  			t.Logf("Saw expected panic '%v'", r)
   775  			if !slices.Equal(expect, result) {
   776  				t.Errorf("Expected %v, got %v", expect, result)
   777  			}
   778  		} else {
   779  			t.Errorf("Wanted to see a failure, result was %v", result)
   780  		}
   781  	}()
   782  
   783  W:
   784  	for _, w := range OfSliceIndex([]int{1000, 2000}) {
   785  		result = append(result, w)
   786  		if w == 2000 {
   787  			break
   788  		}
   789  		for _, x := range OfSliceIndex([]int{100, 200, 300, 400}) {
   790  			for _, y := range OfSliceIndex([]int{10, 20, 30, 40}) {
   791  				result = append(result, y)
   792  				for _, z := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   793  					if z&1 == 1 {
   794  						continue
   795  					}
   796  					result = append(result, z)
   797  					if z >= 4 {
   798  						break W
   799  					}
   800  				}
   801  				result = append(result, -y) // should never be executed
   802  			}
   803  			result = append(result, x)
   804  		}
   805  	}
   806  	if !slices.Equal(expect, result) {
   807  		t.Errorf("Expected %v, got %v", expect, result)
   808  	}
   809  }
   810  
   811  // veryBad tests that a loop nest behaves sensibly in the face of a
   812  // "very bad" iterator.  In this case, "sensibly" means that the
   813  // break out of X still occurs after the very bad iterator finally
   814  // quits running (the control flow bread crumbs remain.)
   815  func veryBad(s []int) []int {
   816  	var result []int
   817  X:
   818  	for _, x := range OfSliceIndex([]int{1, 2, 3}) {
   819  
   820  		result = append(result, x)
   821  
   822  		for _, y := range VeryBadOfSliceIndex(s) {
   823  			result = append(result, y)
   824  			break X
   825  		}
   826  		for _, z := range OfSliceIndex([]int{100, 200, 300}) {
   827  			result = append(result, z)
   828  			if z == 100 {
   829  				break
   830  			}
   831  		}
   832  	}
   833  	return result
   834  }
   835  
   836  // checkVeryBad wraps a "very bad" iterator with Check,
   837  // demonstrating that the very bad iterator also hides panics
   838  // thrown by Check.
   839  func checkVeryBad(s []int) []int {
   840  	var result []int
   841  X:
   842  	for _, x := range OfSliceIndex([]int{1, 2, 3}) {
   843  
   844  		result = append(result, x)
   845  
   846  		for _, y := range Check(VeryBadOfSliceIndex(s)) {
   847  			result = append(result, y)
   848  			break X
   849  		}
   850  		for _, z := range OfSliceIndex([]int{100, 200, 300}) {
   851  			result = append(result, z)
   852  			if z == 100 {
   853  				break
   854  			}
   855  		}
   856  	}
   857  	return result
   858  }
   859  
   860  // okay is the not-bad version of veryBad.
   861  // They should behave the same.
   862  func okay(s []int) []int {
   863  	var result []int
   864  X:
   865  	for _, x := range OfSliceIndex([]int{1, 2, 3}) {
   866  
   867  		result = append(result, x)
   868  
   869  		for _, y := range OfSliceIndex(s) {
   870  			result = append(result, y)
   871  			break X
   872  		}
   873  		for _, z := range OfSliceIndex([]int{100, 200, 300}) {
   874  			result = append(result, z)
   875  			if z == 100 {
   876  				break
   877  			}
   878  		}
   879  	}
   880  	return result
   881  }
   882  
   883  // TestVeryBad1 checks the behavior of an extremely poorly behaved iterator.
   884  func TestVeryBad1(t *testing.T) {
   885  	result := veryBad([]int{10, 20, 30, 40, 50}) // odd length
   886  	expect := []int{1, 10}
   887  
   888  	if !slices.Equal(expect, result) {
   889  		t.Errorf("Expected %v, got %v", expect, result)
   890  	}
   891  }
   892  
   893  // TestVeryBad2 checks the behavior of an extremely poorly behaved iterator.
   894  func TestVeryBad2(t *testing.T) {
   895  	result := veryBad([]int{10, 20, 30, 40}) // even length
   896  	expect := []int{1, 10}
   897  
   898  	if !slices.Equal(expect, result) {
   899  		t.Errorf("Expected %v, got %v", expect, result)
   900  	}
   901  }
   902  
   903  // TestCheckVeryBad checks the behavior of an extremely poorly behaved iterator,
   904  // which also suppresses the exceptions from "Check"
   905  func TestCheckVeryBad(t *testing.T) {
   906  	result := checkVeryBad([]int{10, 20, 30, 40}) // even length
   907  	expect := []int{1, 10}
   908  
   909  	if !slices.Equal(expect, result) {
   910  		t.Errorf("Expected %v, got %v", expect, result)
   911  	}
   912  }
   913  
   914  // TestOk is the nice version of the very bad iterator.
   915  func TestOk(t *testing.T) {
   916  	result := okay([]int{10, 20, 30, 40, 50}) // odd length
   917  	expect := []int{1, 10}
   918  
   919  	if !slices.Equal(expect, result) {
   920  		t.Errorf("Expected %v, got %v", expect, result)
   921  	}
   922  }
   923  
   924  // testBreak1BadDefer checks that defer behaves properly even in
   925  // the presence of loop bodies panicking out of bad iterators.
   926  // (i.e., the instrumentation did not break defer in these loops)
   927  func testBreak1BadDefer(t *testing.T) (result []int) {
   928  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3, -30, -20, -10}
   929  
   930  	defer func() {
   931  		if r := recover(); r != nil {
   932  			t.Logf("Saw expected panic '%v'", r)
   933  			if !slices.Equal(expect, result) {
   934  				t.Errorf("(Inner) Expected %v, got %v", expect, result)
   935  			}
   936  		} else {
   937  			t.Error("Wanted to see a failure")
   938  		}
   939  	}()
   940  
   941  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   942  		if x == -4 {
   943  			break
   944  		}
   945  		defer func() {
   946  			result = append(result, x*10)
   947  		}()
   948  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   949  			if y == 3 {
   950  				break
   951  			}
   952  			result = append(result, y)
   953  		}
   954  		result = append(result, x)
   955  	}
   956  	return
   957  }
   958  
   959  func TestBreak1BadDefer(t *testing.T) {
   960  	var result []int
   961  	var expect = []int{1, 2, -1, 1, 2, -2, 1, 2, -3, -30, -20, -10}
   962  	result = testBreak1BadDefer(t)
   963  	if !slices.Equal(expect, result) {
   964  		t.Errorf("(Outer) Expected %v, got %v", expect, result)
   965  	}
   966  }
   967  
   968  // testReturn1 has no bad iterators.
   969  func testReturn1(t *testing.T) (result []int, err any) {
   970  	defer func() {
   971  		err = recover()
   972  	}()
   973  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   974  		result = append(result, x)
   975  		if x == -4 {
   976  			break
   977  		}
   978  		defer func() {
   979  			result = append(result, x*10)
   980  		}()
   981  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
   982  			if y == 3 {
   983  				return
   984  			}
   985  			result = append(result, y)
   986  		}
   987  		result = append(result, x)
   988  	}
   989  	return
   990  }
   991  
   992  // testReturn2 has an outermost bad iterator
   993  func testReturn2(t *testing.T) (result []int, err any) {
   994  	defer func() {
   995  		err = recover()
   996  	}()
   997  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
   998  		result = append(result, x)
   999  		if x == -4 {
  1000  			break
  1001  		}
  1002  		defer func() {
  1003  			result = append(result, x*10)
  1004  		}()
  1005  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1006  			if y == 3 {
  1007  				return
  1008  			}
  1009  			result = append(result, y)
  1010  		}
  1011  		result = append(result, x)
  1012  	}
  1013  	return
  1014  }
  1015  
  1016  // testReturn3 has an innermost bad iterator
  1017  func testReturn3(t *testing.T) (result []int, err any) {
  1018  	defer func() {
  1019  		err = recover()
  1020  	}()
  1021  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1022  		result = append(result, x)
  1023  		if x == -4 {
  1024  			break
  1025  		}
  1026  		defer func() {
  1027  			result = append(result, x*10)
  1028  		}()
  1029  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1030  			if y == 3 {
  1031  				return
  1032  			}
  1033  			result = append(result, y)
  1034  		}
  1035  	}
  1036  	return
  1037  }
  1038  
  1039  // TestReturns checks that returns through bad iterators behave properly,
  1040  // for inner and outer bad iterators.
  1041  func TestReturns(t *testing.T) {
  1042  	var result []int
  1043  	var expect = []int{-1, 1, 2, -10}
  1044  	var err any
  1045  
  1046  	result, err = testReturn1(t)
  1047  	if !slices.Equal(expect, result) {
  1048  		t.Errorf("Expected %v, got %v", expect, result)
  1049  	}
  1050  	if err != nil {
  1051  		t.Errorf("Unexpected error %v", err)
  1052  	}
  1053  
  1054  	result, err = testReturn2(t)
  1055  	if !slices.Equal(expect, result) {
  1056  		t.Errorf("Expected %v, got %v", expect, result)
  1057  	}
  1058  	if err == nil {
  1059  		t.Errorf("Missing expected error")
  1060  	} else {
  1061  		t.Logf("Saw expected panic '%v'", err)
  1062  	}
  1063  
  1064  	result, err = testReturn3(t)
  1065  	if !slices.Equal(expect, result) {
  1066  		t.Errorf("Expected %v, got %v", expect, result)
  1067  	}
  1068  	if err == nil {
  1069  		t.Errorf("Missing expected error")
  1070  	} else {
  1071  		t.Logf("Saw expected panic '%v'", err)
  1072  	}
  1073  
  1074  }
  1075  
  1076  // testGotoA1 tests loop-nest-internal goto, no bad iterators.
  1077  func testGotoA1(t *testing.T) (result []int, err any) {
  1078  	defer func() {
  1079  		err = recover()
  1080  	}()
  1081  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1082  		result = append(result, x)
  1083  		if x == -4 {
  1084  			break
  1085  		}
  1086  		defer func() {
  1087  			result = append(result, x*10)
  1088  		}()
  1089  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1090  			if y == 3 {
  1091  				goto A
  1092  			}
  1093  			result = append(result, y)
  1094  		}
  1095  		result = append(result, x)
  1096  	A:
  1097  	}
  1098  	return
  1099  }
  1100  
  1101  // testGotoA2 tests loop-nest-internal goto, outer bad iterator.
  1102  func testGotoA2(t *testing.T) (result []int, err any) {
  1103  	defer func() {
  1104  		err = recover()
  1105  	}()
  1106  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1107  		result = append(result, x)
  1108  		if x == -4 {
  1109  			break
  1110  		}
  1111  		defer func() {
  1112  			result = append(result, x*10)
  1113  		}()
  1114  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1115  			if y == 3 {
  1116  				goto A
  1117  			}
  1118  			result = append(result, y)
  1119  		}
  1120  		result = append(result, x)
  1121  	A:
  1122  	}
  1123  	return
  1124  }
  1125  
  1126  // testGotoA3 tests loop-nest-internal goto, inner bad iterator.
  1127  func testGotoA3(t *testing.T) (result []int, err any) {
  1128  	defer func() {
  1129  		err = recover()
  1130  	}()
  1131  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1132  		result = append(result, x)
  1133  		if x == -4 {
  1134  			break
  1135  		}
  1136  		defer func() {
  1137  			result = append(result, x*10)
  1138  		}()
  1139  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1140  			if y == 3 {
  1141  				goto A
  1142  			}
  1143  			result = append(result, y)
  1144  		}
  1145  		result = append(result, x)
  1146  	A:
  1147  	}
  1148  	return
  1149  }
  1150  
  1151  func TestGotoA(t *testing.T) {
  1152  	var result []int
  1153  	var expect = []int{-1, 1, 2, -2, 1, 2, -3, 1, 2, -4, -30, -20, -10}
  1154  	var expect3 = []int{-1, 1, 2, -10} // first goto becomes a panic
  1155  	var err any
  1156  
  1157  	result, err = testGotoA1(t)
  1158  	if !slices.Equal(expect, result) {
  1159  		t.Errorf("Expected %v, got %v", expect, result)
  1160  	}
  1161  	if err != nil {
  1162  		t.Errorf("Unexpected error %v", err)
  1163  	}
  1164  
  1165  	result, err = testGotoA2(t)
  1166  	if !slices.Equal(expect, result) {
  1167  		t.Errorf("Expected %v, got %v", expect, result)
  1168  	}
  1169  	if err == nil {
  1170  		t.Errorf("Missing expected error")
  1171  	} else {
  1172  		t.Logf("Saw expected panic '%v'", err)
  1173  	}
  1174  
  1175  	result, err = testGotoA3(t)
  1176  	if !slices.Equal(expect3, result) {
  1177  		t.Errorf("Expected %v, got %v", expect3, result)
  1178  	}
  1179  	if err == nil {
  1180  		t.Errorf("Missing expected error")
  1181  	} else {
  1182  		t.Logf("Saw expected panic '%v'", err)
  1183  	}
  1184  }
  1185  
  1186  // testGotoB1 tests loop-nest-exiting goto, no bad iterators.
  1187  func testGotoB1(t *testing.T) (result []int, err any) {
  1188  	defer func() {
  1189  		err = recover()
  1190  	}()
  1191  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1192  		result = append(result, x)
  1193  		if x == -4 {
  1194  			break
  1195  		}
  1196  		defer func() {
  1197  			result = append(result, x*10)
  1198  		}()
  1199  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1200  			if y == 3 {
  1201  				goto B
  1202  			}
  1203  			result = append(result, y)
  1204  		}
  1205  		result = append(result, x)
  1206  	}
  1207  B:
  1208  	result = append(result, 999)
  1209  	return
  1210  }
  1211  
  1212  // testGotoB2 tests loop-nest-exiting goto, outer bad iterator.
  1213  func testGotoB2(t *testing.T) (result []int, err any) {
  1214  	defer func() {
  1215  		err = recover()
  1216  	}()
  1217  	for _, x := range BadOfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1218  		result = append(result, x)
  1219  		if x == -4 {
  1220  			break
  1221  		}
  1222  		defer func() {
  1223  			result = append(result, x*10)
  1224  		}()
  1225  		for _, y := range OfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1226  			if y == 3 {
  1227  				goto B
  1228  			}
  1229  			result = append(result, y)
  1230  		}
  1231  		result = append(result, x)
  1232  	}
  1233  B:
  1234  	result = append(result, 999)
  1235  	return
  1236  }
  1237  
  1238  // testGotoB3 tests loop-nest-exiting goto, inner bad iterator.
  1239  func testGotoB3(t *testing.T) (result []int, err any) {
  1240  	defer func() {
  1241  		err = recover()
  1242  	}()
  1243  	for _, x := range OfSliceIndex([]int{-1, -2, -3, -4, -5}) {
  1244  		result = append(result, x)
  1245  		if x == -4 {
  1246  			break
  1247  		}
  1248  		defer func() {
  1249  			result = append(result, x*10)
  1250  		}()
  1251  		for _, y := range BadOfSliceIndex([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
  1252  			if y == 3 {
  1253  				goto B
  1254  			}
  1255  			result = append(result, y)
  1256  		}
  1257  		result = append(result, x)
  1258  	}
  1259  B:
  1260  	result = append(result, 999)
  1261  	return
  1262  }
  1263  
  1264  func TestGotoB(t *testing.T) {
  1265  	var result []int
  1266  	var expect = []int{-1, 1, 2, 999, -10}
  1267  	var expectX = []int{-1, 1, 2, -10}
  1268  	var err any
  1269  
  1270  	result, err = testGotoB1(t)
  1271  	if !slices.Equal(expect, result) {
  1272  		t.Errorf("Expected %v, got %v", expect, result)
  1273  	}
  1274  	if err != nil {
  1275  		t.Errorf("Unexpected error %v", err)
  1276  	}
  1277  
  1278  	result, err = testGotoB2(t)
  1279  	if !slices.Equal(expectX, result) {
  1280  		t.Errorf("Expected %v, got %v", expectX, result)
  1281  	}
  1282  	if err == nil {
  1283  		t.Errorf("Missing expected error")
  1284  	} else {
  1285  		t.Logf("Saw expected panic '%v'", err)
  1286  	}
  1287  
  1288  	result, err = testGotoB3(t)
  1289  	if !slices.Equal(expectX, result) {
  1290  		t.Errorf("Expected %v, got %v", expectX, result)
  1291  	}
  1292  	if err == nil {
  1293  		t.Errorf("Missing expected error")
  1294  	} else {
  1295  		t.Logf("Saw expected panic '%v'", err)
  1296  	}
  1297  }
  1298  

View as plain text