modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/chan/select5.go (about)

     1  // runoutput
     2  
     3  // Copyright 2011 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Generate test of channel operations and simple selects.
     8  // The output of this program is compiled and run to do the
     9  // actual test.
    10  
    11  // Each test does only one real send or receive at a time, but phrased
    12  // in various ways that the compiler may or may not rewrite
    13  // into simpler expressions.
    14  
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"text/template"
    23  )
    24  
    25  func main() {
    26  	out := bufio.NewWriter(os.Stdout)
    27  	fmt.Fprintln(out, header)
    28  	a := new(arg)
    29  
    30  	// Generate each test as a separate function to avoid
    31  	// hitting the gc optimizer with one enormous function.
    32  	// If we name all the functions init we don't have to
    33  	// maintain a list of which ones to run.
    34  	do := func(t *template.Template) {
    35  		for ; next(); a.reset() {
    36  			fmt.Fprintln(out, `func init() {`)
    37  			run(t, a, out)
    38  			fmt.Fprintln(out, `}`)
    39  		}
    40  	}
    41  
    42  	do(recv)
    43  	do(send)
    44  	do(recvOrder)
    45  	do(sendOrder)
    46  	do(nonblock)
    47  
    48  	fmt.Fprintln(out, "//", a.nreset, "cases")
    49  	out.Flush()
    50  }
    51  
    52  func run(t *template.Template, a interface{}, out io.Writer) {
    53  	if err := t.Execute(out, a); err != nil {
    54  		panic(err)
    55  	}
    56  }
    57  
    58  type arg struct {
    59  	def    bool
    60  	nreset int
    61  }
    62  
    63  func (a *arg) Maybe() bool {
    64  	return maybe()
    65  }
    66  
    67  func (a *arg) MaybeDefault() bool {
    68  	if a.def {
    69  		return false
    70  	}
    71  	a.def = maybe()
    72  	return a.def
    73  }
    74  
    75  func (a *arg) MustDefault() bool {
    76  	return !a.def
    77  }
    78  
    79  func (a *arg) reset() {
    80  	a.def = false
    81  	a.nreset++
    82  }
    83  
    84  const header = `// GENERATED BY select5.go; DO NOT EDIT
    85  
    86  package main
    87  
    88  // channel is buffered so test is single-goroutine.
    89  // we are not interested in the concurrency aspects
    90  // of select, just testing that the right calls happen.
    91  var c = make(chan int, 1)
    92  var nilch chan int
    93  var n = 1
    94  var x int
    95  var i interface{}
    96  var dummy = make(chan int)
    97  var m = make(map[int]int)
    98  var order = 0
    99  
   100  func f(p *int) *int {
   101  	return p
   102  }
   103  
   104  // check order of operations by ensuring that
   105  // successive calls to checkorder have increasing o values.
   106  func checkorder(o int) {
   107  	if o <= order {
   108  		println("invalid order", o, "after", order)
   109  		panic("order")
   110  	}
   111  	order = o
   112  }
   113  
   114  func fc(c chan int, o int) chan int {
   115  	checkorder(o)
   116  	return c
   117  }
   118  
   119  func fp(p *int, o int) *int {
   120  	checkorder(o)
   121  	return p
   122  }
   123  
   124  func fn(n, o int) int {
   125  	checkorder(o)
   126  	return n
   127  }
   128  
   129  func die(x int) {
   130  	println("have", x, "want", n)
   131  	panic("chan")
   132  }
   133  
   134  func main() {
   135  	// everything happens in init funcs
   136  }
   137  `
   138  
   139  func parse(name, s string) *template.Template {
   140  	t, err := template.New(name).Parse(s)
   141  	if err != nil {
   142  		panic(fmt.Sprintf("%q: %s", name, err))
   143  	}
   144  	return t
   145  }
   146  
   147  var recv = parse("recv", `
   148  	{{/*  Send n, receive it one way or another into x, check that they match. */}}
   149  	c <- n
   150  	{{if .Maybe}}
   151  	x = <-c
   152  	{{else}}
   153  	select {
   154  	{{/*  Blocking or non-blocking, before the receive. */}}
   155  	{{/*  The compiler implements two-case select where one is default with custom code, */}}
   156  	{{/*  so test the default branch both before and after the send. */}}
   157  	{{if .MaybeDefault}}
   158  	default:
   159  		panic("nonblock")
   160  	{{end}}
   161  	{{/*  Receive from c.  Different cases are direct, indirect, :=, interface, and map assignment. */}}
   162  	{{if .Maybe}}
   163  	case x = <-c:
   164  	{{else}}{{if .Maybe}}
   165  	case *f(&x) = <-c:
   166  	{{else}}{{if .Maybe}}
   167  	case y := <-c:
   168  		x = y
   169  	{{else}}{{if .Maybe}}
   170  	case i = <-c:
   171  		x = i.(int)
   172  	{{else}}
   173  	case m[13] = <-c:
   174  		x = m[13]
   175  	{{end}}{{end}}{{end}}{{end}}
   176  	{{/*  Blocking or non-blocking again, after the receive. */}}
   177  	{{if .MaybeDefault}}
   178  	default:
   179  		panic("nonblock")
   180  	{{end}}
   181  	{{/*  Dummy send, receive to keep compiler from optimizing select. */}}
   182  	{{if .Maybe}}
   183  	case dummy <- 1:
   184  		panic("dummy send")
   185  	{{end}}
   186  	{{if .Maybe}}
   187  	case <-dummy:
   188  		panic("dummy receive")
   189  	{{end}}
   190  	{{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
   191  	{{if .Maybe}}
   192  	case nilch <- 1:
   193  		panic("nilch send")
   194  	{{end}}
   195  	{{if .Maybe}}
   196  	case <-nilch:
   197  		panic("nilch recv")
   198  	{{end}}
   199  	}
   200  	{{end}}
   201  	if x != n {
   202  		die(x)
   203  	}
   204  	n++
   205  `)
   206  
   207  var recvOrder = parse("recvOrder", `
   208  	{{/*  Send n, receive it one way or another into x, check that they match. */}}
   209  	{{/*  Check order of operations along the way by calling functions that check */}}
   210  	{{/*  that the argument sequence is strictly increasing. */}}
   211  	order = 0
   212  	c <- n
   213  	{{if .Maybe}}
   214  	{{/*  Outside of select, left-to-right rule applies. */}}
   215  	{{/*  (Inside select, assignment waits until case is chosen, */}}
   216  	{{/*  so right hand side happens before anything on left hand side. */}}
   217  	*fp(&x, 1) = <-fc(c, 2)
   218  	{{else}}{{if .Maybe}}
   219  	m[fn(13, 1)] = <-fc(c, 2)
   220  	x = m[13]
   221  	{{else}}
   222  	select {
   223  	{{/*  Blocking or non-blocking, before the receive. */}}
   224  	{{/*  The compiler implements two-case select where one is default with custom code, */}}
   225  	{{/*  so test the default branch both before and after the send. */}}
   226  	{{if .MaybeDefault}}
   227  	default:
   228  		panic("nonblock")
   229  	{{end}}
   230  	{{/*  Receive from c.  Different cases are direct, indirect, :=, interface, and map assignment. */}}
   231  	{{if .Maybe}}
   232  	case *fp(&x, 100) = <-fc(c, 1):
   233  	{{else}}{{if .Maybe}}
   234  	case y := <-fc(c, 1):
   235  		x = y
   236  	{{else}}{{if .Maybe}}
   237  	case i = <-fc(c, 1):
   238  		x = i.(int)
   239  	{{else}}
   240  	case m[fn(13, 100)] = <-fc(c, 1):
   241  		x = m[13]
   242  	{{end}}{{end}}{{end}}
   243  	{{/*  Blocking or non-blocking again, after the receive. */}}
   244  	{{if .MaybeDefault}}
   245  	default:
   246  		panic("nonblock")
   247  	{{end}}
   248  	{{/*  Dummy send, receive to keep compiler from optimizing select. */}}
   249  	{{if .Maybe}}
   250  	case fc(dummy, 2) <- fn(1, 3):
   251  		panic("dummy send")
   252  	{{end}}
   253  	{{if .Maybe}}
   254  	case <-fc(dummy, 4):
   255  		panic("dummy receive")
   256  	{{end}}
   257  	{{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
   258  	{{if .Maybe}}
   259  	case fc(nilch, 5) <- fn(1, 6):
   260  		panic("nilch send")
   261  	{{end}}
   262  	{{if .Maybe}}
   263  	case <-fc(nilch, 7):
   264  		panic("nilch recv")
   265  	{{end}}
   266  	}
   267  	{{end}}{{end}}
   268  	if x != n {
   269  		die(x)
   270  	}
   271  	n++
   272  `)
   273  
   274  var send = parse("send", `
   275  	{{/*  Send n one way or another, receive it into x, check that they match. */}}
   276  	{{if .Maybe}}
   277  	c <- n
   278  	{{else}}
   279  	select {
   280  	{{/*  Blocking or non-blocking, before the receive (same reason as in recv). */}}
   281  	{{if .MaybeDefault}}
   282  	default:
   283  		panic("nonblock")
   284  	{{end}}
   285  	{{/*  Send c <- n.  No real special cases here, because no values come back */}}
   286  	{{/*  from the send operation. */}}
   287  	case c <- n:
   288  	{{/*  Blocking or non-blocking. */}}
   289  	{{if .MaybeDefault}}
   290  	default:
   291  		panic("nonblock")
   292  	{{end}}
   293  	{{/*  Dummy send, receive to keep compiler from optimizing select. */}}
   294  	{{if .Maybe}}
   295  	case dummy <- 1:
   296  		panic("dummy send")
   297  	{{end}}
   298  	{{if .Maybe}}
   299  	case <-dummy:
   300  		panic("dummy receive")
   301  	{{end}}
   302  	{{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
   303  	{{if .Maybe}}
   304  	case nilch <- 1:
   305  		panic("nilch send")
   306  	{{end}}
   307  	{{if .Maybe}}
   308  	case <-nilch:
   309  		panic("nilch recv")
   310  	{{end}}
   311  	}
   312  	{{end}}
   313  	x = <-c
   314  	if x != n {
   315  		die(x)
   316  	}
   317  	n++
   318  `)
   319  
   320  var sendOrder = parse("sendOrder", `
   321  	{{/*  Send n one way or another, receive it into x, check that they match. */}}
   322  	{{/*  Check order of operations along the way by calling functions that check */}}
   323  	{{/*  that the argument sequence is strictly increasing. */}}
   324  	order = 0
   325  	{{if .Maybe}}
   326  	fc(c, 1) <- fn(n, 2)
   327  	{{else}}
   328  	select {
   329  	{{/*  Blocking or non-blocking, before the receive (same reason as in recv). */}}
   330  	{{if .MaybeDefault}}
   331  	default:
   332  		panic("nonblock")
   333  	{{end}}
   334  	{{/*  Send c <- n.  No real special cases here, because no values come back */}}
   335  	{{/*  from the send operation. */}}
   336  	case fc(c, 1) <- fn(n, 2):
   337  	{{/*  Blocking or non-blocking. */}}
   338  	{{if .MaybeDefault}}
   339  	default:
   340  		panic("nonblock")
   341  	{{end}}
   342  	{{/*  Dummy send, receive to keep compiler from optimizing select. */}}
   343  	{{if .Maybe}}
   344  	case fc(dummy, 3) <- fn(1, 4):
   345  		panic("dummy send")
   346  	{{end}}
   347  	{{if .Maybe}}
   348  	case <-fc(dummy, 5):
   349  		panic("dummy receive")
   350  	{{end}}
   351  	{{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
   352  	{{if .Maybe}}
   353  	case fc(nilch, 6) <- fn(1, 7):
   354  		panic("nilch send")
   355  	{{end}}
   356  	{{if .Maybe}}
   357  	case <-fc(nilch, 8):
   358  		panic("nilch recv")
   359  	{{end}}
   360  	}
   361  	{{end}}
   362  	x = <-c
   363  	if x != n {
   364  		die(x)
   365  	}
   366  	n++
   367  `)
   368  
   369  var nonblock = parse("nonblock", `
   370  	x = n
   371  	{{/*  Test various combinations of non-blocking operations. */}}
   372  	{{/*  Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
   373  	select {
   374  	{{if .MaybeDefault}}
   375  	default:
   376  	{{end}}
   377  	{{if .Maybe}}
   378  	case dummy <- 1:
   379  		panic("dummy <- 1")
   380  	{{end}}
   381  	{{if .Maybe}}
   382  	case nilch <- 1:
   383  		panic("nilch <- 1")
   384  	{{end}}
   385  	{{if .Maybe}}
   386  	case <-dummy:
   387  		panic("<-dummy")
   388  	{{end}}
   389  	{{if .Maybe}}
   390  	case x = <-dummy:
   391  		panic("<-dummy x")
   392  	{{end}}
   393  	{{if .Maybe}}
   394  	case **(**int)(nil) = <-dummy:
   395  		panic("<-dummy (and didn't crash saving result!)")
   396  	{{end}}
   397  	{{if .Maybe}}
   398  	case <-nilch:
   399  		panic("<-nilch")
   400  	{{end}}
   401  	{{if .Maybe}}
   402  	case x = <-nilch:
   403  		panic("<-nilch x")
   404  	{{end}}
   405  	{{if .Maybe}}
   406  	case **(**int)(nil) = <-nilch:
   407  		panic("<-nilch (and didn't crash saving result!)")
   408  	{{end}}
   409  	{{if .MustDefault}}
   410  	default:
   411  	{{end}}
   412  	}
   413  	if x != n {
   414  		die(x)
   415  	}
   416  	n++
   417  `)
   418  
   419  // Code for enumerating all possible paths through
   420  // some logic.  The logic should call choose(n) when
   421  // it wants to choose between n possibilities.
   422  // On successive runs through the logic, choose(n)
   423  // will return 0, 1, ..., n-1.  The helper maybe() is
   424  // similar but returns true and then false.
   425  //
   426  // Given a function gen that generates an output
   427  // using choose and maybe, code can generate all
   428  // possible outputs using
   429  //
   430  //	for next() {
   431  //		gen()
   432  //	}
   433  
   434  type choice struct {
   435  	i, n int
   436  }
   437  
   438  var choices []choice
   439  var cp int = -1
   440  
   441  func maybe() bool {
   442  	return choose(2) == 0
   443  }
   444  
   445  func choose(n int) int {
   446  	if cp >= len(choices) {
   447  		// never asked this before: start with 0.
   448  		choices = append(choices, choice{0, n})
   449  		cp = len(choices)
   450  		return 0
   451  	}
   452  	// otherwise give recorded answer
   453  	if n != choices[cp].n {
   454  		panic("inconsistent choices")
   455  	}
   456  	i := choices[cp].i
   457  	cp++
   458  	return i
   459  }
   460  
   461  func next() bool {
   462  	if cp < 0 {
   463  		// start a new round
   464  		cp = 0
   465  		return true
   466  	}
   467  
   468  	// increment last choice sequence
   469  	cp = len(choices) - 1
   470  	for cp >= 0 && choices[cp].i == choices[cp].n-1 {
   471  		cp--
   472  	}
   473  	if cp < 0 {
   474  		choices = choices[:0]
   475  		return false
   476  	}
   477  	choices[cp].i++
   478  	choices = choices[:cp+1]
   479  	cp = 0
   480  	return true
   481  }