github.com/jd-ly/tools@v0.5.7/go/ssa/interp/testdata/coverage.go (about)

     1  // This interpreter test is designed to run very quickly yet provide
     2  // some coverage of a broad selection of constructs.
     3  //
     4  // Validate this file with 'go run' after editing.
     5  // TODO(adonovan): break this into small files organized by theme.
     6  
     7  package main
     8  
     9  import (
    10  	"fmt"
    11  	"reflect"
    12  	"strings"
    13  )
    14  
    15  func init() {
    16  	// Call of variadic function with (implicit) empty slice.
    17  	if x := fmt.Sprint(); x != "" {
    18  		panic(x)
    19  	}
    20  }
    21  
    22  type empty interface{}
    23  
    24  type I interface {
    25  	f() int
    26  }
    27  
    28  type T struct{ z int }
    29  
    30  func (t T) f() int { return t.z }
    31  
    32  func use(interface{}) {}
    33  
    34  var counter = 2
    35  
    36  // Test initialization, including init blocks containing 'return'.
    37  // Assertion is in main.
    38  func init() {
    39  	counter *= 3
    40  	return
    41  	counter *= 3
    42  }
    43  
    44  func init() {
    45  	counter *= 5
    46  	return
    47  	counter *= 5
    48  }
    49  
    50  // Recursion.
    51  func fib(x int) int {
    52  	if x < 2 {
    53  		return x
    54  	}
    55  	return fib(x-1) + fib(x-2)
    56  }
    57  
    58  func fibgen(ch chan int) {
    59  	for x := 0; x < 10; x++ {
    60  		ch <- fib(x)
    61  	}
    62  	close(ch)
    63  }
    64  
    65  // Goroutines and channels.
    66  func init() {
    67  	ch := make(chan int)
    68  	go fibgen(ch)
    69  	var fibs []int
    70  	for v := range ch {
    71  		fibs = append(fibs, v)
    72  		if len(fibs) == 10 {
    73  			break
    74  		}
    75  	}
    76  	if x := fmt.Sprint(fibs); x != "[0 1 1 2 3 5 8 13 21 34]" {
    77  		panic(x)
    78  	}
    79  }
    80  
    81  // Test of aliasing.
    82  func init() {
    83  	type S struct {
    84  		a, b string
    85  	}
    86  
    87  	s1 := []string{"foo", "bar"}
    88  	s2 := s1 // creates an alias
    89  	s2[0] = "wiz"
    90  	if x := fmt.Sprint(s1, s2); x != "[wiz bar] [wiz bar]" {
    91  		panic(x)
    92  	}
    93  
    94  	pa1 := &[2]string{"foo", "bar"}
    95  	pa2 := pa1 // creates an alias
    96  	pa2[0] = "wiz"
    97  	if x := fmt.Sprint(*pa1, *pa2); x != "[wiz bar] [wiz bar]" {
    98  		panic(x)
    99  	}
   100  
   101  	a1 := [2]string{"foo", "bar"}
   102  	a2 := a1 // creates a copy
   103  	a2[0] = "wiz"
   104  	if x := fmt.Sprint(a1, a2); x != "[foo bar] [wiz bar]" {
   105  		panic(x)
   106  	}
   107  
   108  	t1 := S{"foo", "bar"}
   109  	t2 := t1 // copy
   110  	t2.a = "wiz"
   111  	if x := fmt.Sprint(t1, t2); x != "{foo bar} {wiz bar}" {
   112  		panic(x)
   113  	}
   114  }
   115  
   116  func main() {
   117  	print() // legal
   118  
   119  	if counter != 2*3*5 {
   120  		panic(counter)
   121  	}
   122  
   123  	// Test builtins (e.g. complex) preserve named argument types.
   124  	type N complex128
   125  	var n N
   126  	n = complex(1.0, 2.0)
   127  	if n != complex(1.0, 2.0) {
   128  		panic(n)
   129  	}
   130  	if x := reflect.TypeOf(n).String(); x != "main.N" {
   131  		panic(x)
   132  	}
   133  	if real(n) != 1.0 || imag(n) != 2.0 {
   134  		panic(n)
   135  	}
   136  
   137  	// Channel + select.
   138  	ch := make(chan int, 1)
   139  	select {
   140  	case ch <- 1:
   141  		// ok
   142  	default:
   143  		panic("couldn't send")
   144  	}
   145  	if <-ch != 1 {
   146  		panic("couldn't receive")
   147  	}
   148  	// A "receive" select-case that doesn't declare its vars.  (regression test)
   149  	anint := 0
   150  	ok := false
   151  	select {
   152  	case anint, ok = <-ch:
   153  	case anint = <-ch:
   154  	default:
   155  	}
   156  	_ = anint
   157  	_ = ok
   158  
   159  	// Anon structs with methods.
   160  	anon := struct{ T }{T: T{z: 1}}
   161  	if x := anon.f(); x != 1 {
   162  		panic(x)
   163  	}
   164  	var i I = anon
   165  	if x := i.f(); x != 1 {
   166  		panic(x)
   167  	}
   168  	// NB. precise output of reflect.Type.String is undefined.
   169  	if x := reflect.TypeOf(i).String(); x != "struct { main.T }" && x != "struct{main.T}" {
   170  		panic(x)
   171  	}
   172  
   173  	// fmt.
   174  	const message = "Hello, World!"
   175  	if fmt.Sprint("Hello", ", ", "World", "!") != message {
   176  		panic("oops")
   177  	}
   178  
   179  	// Type assertion.
   180  	type S struct {
   181  		f int
   182  	}
   183  	var e empty = S{f: 42}
   184  	switch v := e.(type) {
   185  	case S:
   186  		if v.f != 42 {
   187  			panic(v.f)
   188  		}
   189  	default:
   190  		panic(reflect.TypeOf(v))
   191  	}
   192  	if i, ok := e.(I); ok {
   193  		panic(i)
   194  	}
   195  
   196  	// Switch.
   197  	var x int
   198  	switch x {
   199  	case 1:
   200  		panic(x)
   201  		fallthrough
   202  	case 2, 3:
   203  		panic(x)
   204  	default:
   205  		// ok
   206  	}
   207  	// empty switch
   208  	switch {
   209  	}
   210  	// empty switch
   211  	switch {
   212  	default:
   213  	}
   214  	// empty switch
   215  	switch {
   216  	default:
   217  		fallthrough
   218  	case false:
   219  	}
   220  
   221  	// string -> []rune conversion.
   222  	use([]rune("foo"))
   223  
   224  	// Calls of form x.f().
   225  	type S2 struct {
   226  		f func() int
   227  	}
   228  	S2{f: func() int { return 1 }}.f() // field is a func value
   229  	T{}.f()                            // method call
   230  	i.f()                              // interface method invocation
   231  	(interface {
   232  		f() int
   233  	}(T{})).f() // anon interface method invocation
   234  
   235  	// Map lookup.
   236  	if v, ok := map[string]string{}["foo5"]; v != "" || ok {
   237  		panic("oops")
   238  	}
   239  
   240  	// Regression test: implicit address-taken struct literal
   241  	// inside literal map element.
   242  	_ = map[int]*struct{}{0: {}}
   243  }
   244  
   245  type mybool bool
   246  
   247  func (mybool) f() {}
   248  
   249  func init() {
   250  	type mybool bool
   251  	var b mybool
   252  	var i interface{} = b || b // result preserves types of operands
   253  	_ = i.(mybool)
   254  
   255  	i = false && b // result preserves type of "typed" operand
   256  	_ = i.(mybool)
   257  
   258  	i = b || true // result preserves type of "typed" operand
   259  	_ = i.(mybool)
   260  }
   261  
   262  func init() {
   263  	var x, y int
   264  	var b mybool = x == y // x==y is an untyped bool
   265  	b.f()
   266  }
   267  
   268  // Simple closures.
   269  func init() {
   270  	b := 3
   271  	f := func(a int) int {
   272  		return a + b
   273  	}
   274  	b++
   275  	if x := f(1); x != 5 { // 1+4 == 5
   276  		panic(x)
   277  	}
   278  	b++
   279  	if x := f(2); x != 7 { // 2+5 == 7
   280  		panic(x)
   281  	}
   282  	if b := f(1) < 16 || f(2) < 17; !b {
   283  		panic("oops")
   284  	}
   285  }
   286  
   287  // Shifts.
   288  func init() {
   289  	var i int64 = 1
   290  	var u uint64 = 1 << 32
   291  	if x := i << uint32(u); x != 1 {
   292  		panic(x)
   293  	}
   294  	if x := i << uint64(u); x != 0 {
   295  		panic(x)
   296  	}
   297  }
   298  
   299  // Implicit conversion of delete() key operand.
   300  func init() {
   301  	type I interface{}
   302  	m := make(map[I]bool)
   303  	m[1] = true
   304  	m[I(2)] = true
   305  	if len(m) != 2 {
   306  		panic(m)
   307  	}
   308  	delete(m, I(1))
   309  	delete(m, 2)
   310  	if len(m) != 0 {
   311  		panic(m)
   312  	}
   313  }
   314  
   315  // An I->I conversion always succeeds.
   316  func init() {
   317  	var x I
   318  	if I(x) != I(nil) {
   319  		panic("I->I conversion failed")
   320  	}
   321  }
   322  
   323  // An I->I type-assert fails iff the value is nil.
   324  func init() {
   325  	defer func() {
   326  		r := fmt.Sprint(recover())
   327  		// Exact error varies by toolchain.
   328  		if r != "runtime error: interface conversion: interface is nil, not main.I" &&
   329  			r != "interface conversion: interface is nil, not main.I" {
   330  			panic("I->I type assertion succeeded for nil value")
   331  		}
   332  	}()
   333  	var x I
   334  	_ = x.(I)
   335  }
   336  
   337  //////////////////////////////////////////////////////////////////////
   338  // Variadic bridge methods and interface thunks.
   339  
   340  type VT int
   341  
   342  var vcount = 0
   343  
   344  func (VT) f(x int, y ...string) {
   345  	vcount++
   346  	if x != 1 {
   347  		panic(x)
   348  	}
   349  	if len(y) != 2 || y[0] != "foo" || y[1] != "bar" {
   350  		panic(y)
   351  	}
   352  }
   353  
   354  type VS struct {
   355  	VT
   356  }
   357  
   358  type VI interface {
   359  	f(x int, y ...string)
   360  }
   361  
   362  func init() {
   363  	foobar := []string{"foo", "bar"}
   364  	var s VS
   365  	s.f(1, "foo", "bar")
   366  	s.f(1, foobar...)
   367  	if vcount != 2 {
   368  		panic("s.f not called twice")
   369  	}
   370  
   371  	fn := VI.f
   372  	fn(s, 1, "foo", "bar")
   373  	fn(s, 1, foobar...)
   374  	if vcount != 4 {
   375  		panic("I.f not called twice")
   376  	}
   377  }
   378  
   379  // Multiple labels on same statement.
   380  func multipleLabels() {
   381  	var trace []int
   382  	i := 0
   383  one:
   384  two:
   385  	for ; i < 3; i++ {
   386  		trace = append(trace, i)
   387  		switch i {
   388  		case 0:
   389  			continue two
   390  		case 1:
   391  			i++
   392  			goto one
   393  		case 2:
   394  			break two
   395  		}
   396  	}
   397  	if x := fmt.Sprint(trace); x != "[0 1 2]" {
   398  		panic(x)
   399  	}
   400  }
   401  
   402  func init() {
   403  	multipleLabels()
   404  }
   405  
   406  func init() {
   407  	// Struct equivalence ignores blank fields.
   408  	type s struct{ x, _, z int }
   409  	s1 := s{x: 1, z: 3}
   410  	s2 := s{x: 1, z: 3}
   411  	if s1 != s2 {
   412  		panic("not equal")
   413  	}
   414  }
   415  
   416  func init() {
   417  	// A slice var can be compared to const []T nil.
   418  	var i interface{} = []string{"foo"}
   419  	var j interface{} = []string(nil)
   420  	if i.([]string) == nil {
   421  		panic("expected i non-nil")
   422  	}
   423  	if j.([]string) != nil {
   424  		panic("expected j nil")
   425  	}
   426  	// But two slices cannot be compared, even if one is nil.
   427  	defer func() {
   428  		r := fmt.Sprint(recover())
   429  		if !(strings.Contains(r, "compar") && strings.Contains(r, "[]string")) {
   430  			panic("want panic from slice comparison, got " + r)
   431  		}
   432  	}()
   433  	_ = i == j // interface comparison recurses on types
   434  }
   435  
   436  func init() {
   437  	// Regression test for SSA renaming bug.
   438  	var ints []int
   439  	for range "foo" {
   440  		var x int
   441  		x++
   442  		ints = append(ints, x)
   443  	}
   444  	if fmt.Sprint(ints) != "[1 1 1]" {
   445  		panic(ints)
   446  	}
   447  }
   448  
   449  // Regression test for issue 6949:
   450  // []byte("foo") is not a constant since it allocates memory.
   451  func init() {
   452  	var r string
   453  	for i, b := range "ABC" {
   454  		x := []byte("abc")
   455  		x[i] = byte(b)
   456  		r += string(x)
   457  	}
   458  	if r != "AbcaBcabC" {
   459  		panic(r)
   460  	}
   461  }
   462  
   463  // Test of 3-operand x[lo:hi:max] slice.
   464  func init() {
   465  	s := []int{0, 1, 2, 3}
   466  	lenCapLoHi := func(x []int) [4]int { return [4]int{len(x), cap(x), x[0], x[len(x)-1]} }
   467  	if got := lenCapLoHi(s[1:3]); got != [4]int{2, 3, 1, 2} {
   468  		panic(got)
   469  	}
   470  	if got := lenCapLoHi(s[1:3:3]); got != [4]int{2, 2, 1, 2} {
   471  		panic(got)
   472  	}
   473  	max := 3
   474  	if "a"[0] == 'a' {
   475  		max = 2 // max is non-constant, even in SSA form
   476  	}
   477  	if got := lenCapLoHi(s[1:2:max]); got != [4]int{1, 1, 1, 1} {
   478  		panic(got)
   479  	}
   480  }
   481  
   482  var one = 1 // not a constant
   483  
   484  // Test makeslice.
   485  func init() {
   486  	check := func(s []string, wantLen, wantCap int) {
   487  		if len(s) != wantLen {
   488  			panic(len(s))
   489  		}
   490  		if cap(s) != wantCap {
   491  			panic(cap(s))
   492  		}
   493  	}
   494  	//                                       SSA form:
   495  	check(make([]string, 10), 10, 10)     // new([10]string)[:10]
   496  	check(make([]string, one), 1, 1)      // make([]string, one, one)
   497  	check(make([]string, 0, 10), 0, 10)   // new([10]string)[:0]
   498  	check(make([]string, 0, one), 0, 1)   // make([]string, 0, one)
   499  	check(make([]string, one, 10), 1, 10) // new([10]string)[:one]
   500  	check(make([]string, one, one), 1, 1) // make([]string, one, one)
   501  }
   502  
   503  // Test that a nice error is issued by indirection wrappers.
   504  func init() {
   505  	var ptr *T
   506  	var i I = ptr
   507  
   508  	defer func() {
   509  		r := fmt.Sprint(recover())
   510  		// Exact error varies by toolchain:
   511  		if r != "runtime error: value method (main.T).f called using nil *main.T pointer" &&
   512  			r != "value method (main.T).f called using nil *main.T pointer" {
   513  			panic("want panic from call with nil receiver, got " + r)
   514  		}
   515  	}()
   516  	i.f()
   517  	panic("unreachable")
   518  }
   519  
   520  // Regression test for a subtle bug in which copying values would causes
   521  // subcomponents of aggregate variables to change address, breaking
   522  // aliases.
   523  func init() {
   524  	type T struct{ f int }
   525  	var x T
   526  	p := &x.f
   527  	x = T{}
   528  	*p = 1
   529  	if x.f != 1 {
   530  		panic("lost store")
   531  	}
   532  	if p != &x.f {
   533  		panic("unstable address")
   534  	}
   535  }