aboutsummaryrefslogtreecommitdiff
path: root/go/pointer/testdata/channels.go
blob: c4f5150bf4c2bc041f31b7cb3513a2d3f8d45078 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//go:build ignore
// +build ignore

package main

func incr(x int) int { return x + 1 }

func decr(x int) int { return x - 1 }

var unknown bool // defeat dead-code elimination

func chan1() {
	chA := make(chan func(int) int, 0) // @line c1makeA
	chB := make(chan func(int) int, 0) // @line c1makeB
	chA <- incr
	chB <- decr
	chB <- func(int) int { return 1 }

	print(chA)   // @pointsto makechan@c1makeA:13
	print(<-chA) // @pointsto command-line-arguments.incr

	print(chB)   // @pointsto makechan@c1makeB:13
	print(<-chB) // @pointsto command-line-arguments.decr | command-line-arguments.chan1$1
}

func chan2() {
	chA := make(chan func(int) int, 0) // @line c2makeA
	chB := make(chan func(int) int, 0) // @line c2makeB
	chA <- incr
	chB <- decr
	chB <- func(int) int { return 1 }

	// Channels flow together.
	// Labelsets remain distinct but elements are merged.
	chAB := chA
	if unknown {
		chAB = chB
	}

	print(chA)   // @pointsto makechan@c2makeA:13
	print(<-chA) // @pointsto command-line-arguments.incr

	print(chB)   // @pointsto makechan@c2makeB:13
	print(<-chB) // @pointsto command-line-arguments.decr | command-line-arguments.chan2$1

	print(chAB)   // @pointsto makechan@c2makeA:13 | makechan@c2makeB:13
	print(<-chAB) // @pointsto command-line-arguments.incr | command-line-arguments.decr | command-line-arguments.chan2$1

	(<-chA)(3)
}

// @calls command-line-arguments.chan2 -> command-line-arguments.incr

func chan3() {
	chA := make(chan func(int) int, 0) // @line c3makeA
	chB := make(chan func(int) int, 0) // @line c3makeB
	chA <- incr
	chB <- decr
	chB <- func(int) int { return 1 }
	print(chA)   // @pointsto makechan@c3makeA:13
	print(<-chA) // @pointsto command-line-arguments.incr
	print(chB)   // @pointsto makechan@c3makeB:13
	print(<-chB) // @pointsto command-line-arguments.decr | command-line-arguments.chan3$1

	(<-chA)(3)
}

// @calls command-line-arguments.chan3 -> command-line-arguments.incr

func chan4() {
	chA := make(chan func(int) int, 0) // @line c4makeA
	chB := make(chan func(int) int, 0) // @line c4makeB

	select {
	case chA <- incr:
	case chB <- decr:
	case a := <-chA:
		print(a) // @pointsto command-line-arguments.incr
	case b := <-chB:
		print(b) // @pointsto command-line-arguments.decr
	default:
		print(chA) // @pointsto makechan@c4makeA:13
		print(chB) // @pointsto makechan@c4makeB:13
	}

	for k := range chA {
		print(k) // @pointsto command-line-arguments.incr
	}
	// Exercise constraint generation (regtest for a crash).
	for range chA {
	}
}

// Multi-word channel value in select with multiple receive cases.
// (Regtest for a crash.)
func chan5() {
	type T struct {
		x *int
		y interface{}
	}
	ch := make(chan T)
	ch <- T{new(int), incr} // @line ch5new
	select {
	case a := <-ch:
		print(a.x) // @pointsto new@ch5new:13
		print(a.y) // @types func(x int) int
	case b := <-ch:
		print(b.x) // @pointsto new@ch5new:13
		print(b.y) // @types func(x int) int
	}
}

func main() {
	chan1()
	chan2()
	chan3()
	chan4()
	chan5()
}