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 }