GoPLS Viewer

Home|gopls/go/ssa/interp/testdata/coverage.go
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
7package main
8
9import (
10    "fmt"
11    "reflect"
12    "strings"
13)
14
15func init() {
16    // Call of variadic function with (implicit) empty slice.
17    if x := fmt.Sprint(); x != "" {
18        panic(x)
19    }
20}
21
22type empty interface{}
23
24type I interface {
25    f() int
26}
27
28type T struct{ z int }
29
30func (t Tf() int { return t.z }
31
32func use(interface{}) {}
33
34var counter = 2
35
36// Test initialization, including init blocks containing 'return'.
37// Assertion is in main.
38func init() {
39    counter *= 3
40    return
41    counter *= 3
42}
43
44func init() {
45    counter *= 5
46    return
47    counter *= 5
48}
49
50// Recursion.
51func fib(x intint {
52    if x < 2 {
53        return x
54    }
55    return fib(x-1) + fib(x-2)
56}
57
58func fibgen(ch chan int) {
59    for x := 0x < 10x++ {
60        ch <- fib(x)
61    }
62    close(ch)
63}
64
65// Goroutines and channels.
66func init() {
67    ch := make(chan int)
68    go fibgen(ch)
69    var fibs []int
70    for v := range ch {
71        fibs = append(fibsv)
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.
82func init() {
83    type S struct {
84        ab string
85    }
86
87    s1 := []string{"foo""bar"}
88    s2 := s1 // creates an alias
89    s2[0] = "wiz"
90    if x := fmt.Sprint(s1s2); 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(a1a2); 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(t1t2); x != "{foo bar} {wiz bar}" {
112        panic(x)
113    }
114}
115
116func 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.02.0)
127    if n != complex(1.02.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 int1)
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 anintok = <-ch:
153    case anint = <-ch:
154    default:
155    }
156    _ = anint
157    _ = ok
158
159    // Anon structs with methods.
160    anon := struct{ T }{TT{z1}}
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{f42}
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 iok := 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 23:
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 vok := 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
245type mybool bool
246
247func (myboolf() {}
248
249func 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
262func init() {
263    var xy int
264    var b mybool = x == y // x==y is an untyped bool
265    b.f()
266}
267
268// Simple closures.
269func init() {
270    b := 3
271    f := func(a intint {
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.
288func 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.
300func 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(mI(1))
309    delete(m2)
310    if len(m) != 0 {
311        panic(m)
312    }
313}
314
315// An I->I conversion always succeeds.
316func 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.
324func 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
340type VT int
341
342var vcount = 0
343
344func (VTf(x inty ...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
354type VS struct {
355    VT
356}
357
358type VI interface {
359    f(x inty ...string)
360}
361
362func init() {
363    foobar := []string{"foo""bar"}
364    var s VS
365    s.f(1"foo""bar")
366    s.f(1foobar...)
367    if vcount != 2 {
368        panic("s.f not called twice")
369    }
370
371    fn := VI.f
372    fn(s1"foo""bar")
373    fn(s1foobar...)
374    if vcount != 4 {
375        panic("I.f not called twice")
376    }
377}
378
379// Multiple labels on same statement.
380func multipleLabels() {
381    var trace []int
382    i := 0
383one:
384two:
385    for ; i < 3i++ {
386        trace = append(tracei)
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
402func init() {
403    multipleLabels()
404}
405
406func init() {
407    // Struct equivalence ignores blank fields.
408    type s struct{ x_z int }
409    s1 := s{x1z3}
410    s2 := s{x1z3}
411    if s1 != s2 {
412        panic("not equal")
413    }
414}
415
416func 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
436func 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(intsx)
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.
451func init() {
452    var r string
453    for ib := 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.
464func init() {
465    s := []int{0123}
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{2312} {
468        panic(got)
469    }
470    if got := lenCapLoHi(s[1:3:3]); got != [4]int{2212} {
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{1111} {
478        panic(got)
479    }
480}
481
482var one = 1 // not a constant
483
484// Test makeslice.
485func init() {
486    check := func(s []stringwantLenwantCap 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([]string10), 1010)     // new([10]string)[:10]
496    check(make([]stringone), 11)      // make([]string, one, one)
497    check(make([]string010), 010)   // new([10]string)[:0]
498    check(make([]string0one), 01)   // make([]string, 0, one)
499    check(make([]stringone10), 110// new([10]string)[:one]
500    check(make([]stringoneone), 11// make([]string, one, one)
501}
502
503// Test that a nice error is issued by indirection wrappers.
504func 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.
523func 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}
536
MembersX
fibgen.ch
main.BlockStmt.N
init.BlockStmt.y
VT.f
multipleLabels.x
init.BlockStmt.ints
strings
init.BlockStmt.s2
main.BlockStmt.x
main.BlockStmt.ch
main.BlockStmt.anon
init.BlockStmt.u
VT.f.x
init.BlockStmt.s.z
init.BlockStmt.r
one
init.BlockStmt.a1
init.BlockStmt.t2
main.BlockStmt.i
multipleLabels.i
T.f
init.BlockStmt.a2
init.BlockStmt.mybool
init.BlockStmt.foobar
init.BlockStmt.RangeStmt_7653.BlockStmt.x
init.BlockStmt.T
fib.x
init.BlockStmt.I
init.BlockStmt.RangeStmt_7653.i
init.BlockStmt.s.x
init.BlockStmt.RangeStmt_7407.BlockStmt.x
init.BlockStmt.RangeStmt_7653.b
main.BlockStmt.S2.f
T.z
VT
init.BlockStmt.ch
main.BlockStmt.anint
init.BlockStmt.BlockStmt.r
vcount
fib
fibgen.x
init.BlockStmt.fibs
multipleLabels.trace
init.BlockStmt.pa1
init.BlockStmt.pa2
init.BlockStmt.i
init.BlockStmt.got
init.BlockStmt.ptr
reflect
init.BlockStmt.x
T.f.t
init.BlockStmt.s1
main.BlockStmt.n
main.BlockStmt.S
VS
T
use
counter
fibgen
init.BlockStmt.RangeStmt_1053.v
main.BlockStmt.S2
init.BlockStmt.b
init.BlockStmt.t1
mybool
mybool.f
init.BlockStmt.fn
init.BlockStmt.T.f
VI
empty
main.BlockStmt.ok
main.BlockStmt.message
main.BlockStmt.S.f
main.BlockStmt.e
VT.f.y
multipleLabels
init.BlockStmt.max
Members
X