1// +build ignore
2
3package main
4
5type I interface {
6	f()
7}
8
9type C int
10
11func (*C) f() {}
12
13type D struct{ ptr *int }
14
15func (D) f() {}
16
17type E struct{}
18
19func (*E) f() {}
20
21var a, b int
22
23var unknown bool // defeat dead-code elimination
24
25func interface1() {
26	var i interface{} = &a
27	var j interface{} = D{&b}
28	k := j
29	if unknown {
30		k = i
31	}
32
33	print(i) // @types *int
34	print(j) // @types D
35	print(k) // @types *int | D
36
37	print(i.(*int)) // @pointsto main.a
38	print(j.(*int)) // @pointsto
39	print(k.(*int)) // @pointsto main.a
40
41	print(i.(D).ptr) // @pointsto
42	print(j.(D).ptr) // @pointsto main.b
43	print(k.(D).ptr) // @pointsto main.b
44}
45
46func interface2() {
47	var i I = (*C)(&a)
48	var j I = D{&a}
49	k := j
50	if unknown {
51		k = i
52	}
53
54	print(i) // @types *C
55	print(j) // @types D
56	print(k) // @types *C | D
57	print(k) // @pointsto makeinterface:main.D | makeinterface:*main.C
58
59	k.f()
60	// @calls main.interface2 -> (*main.C).f
61	// @calls main.interface2 -> (main.D).f
62
63	print(i.(*C))    // @pointsto main.a
64	print(j.(D).ptr) // @pointsto main.a
65	print(k.(*C))    // @pointsto main.a
66
67	switch x := k.(type) {
68	case *C:
69		print(x) // @pointsto main.a
70	case D:
71		print(x.ptr) // @pointsto main.a
72	case *E:
73		print(x) // @pointsto
74	}
75}
76
77func interface3() {
78	// There should be no backflow of concrete types from the type-switch to x.
79	var x interface{} = 0
80	print(x) // @types int
81	switch x.(type) {
82	case int:
83	case string:
84	}
85}
86
87func interface4() {
88	var i interface{} = D{&a}
89	if unknown {
90		i = 123
91	}
92
93	print(i) // @types int | D
94
95	j := i.(I)       // interface narrowing type-assertion
96	print(j)         // @types D
97	print(j.(D).ptr) // @pointsto main.a
98
99	var l interface{} = j // interface widening assignment.
100	print(l)              // @types D
101	print(l.(D).ptr)      // @pointsto main.a
102
103	m := j.(interface{}) // interface widening type-assertion.
104	print(m)             // @types D
105	print(m.(D).ptr)     // @pointsto main.a
106}
107
108// Interface method calls and value flow:
109
110type J interface {
111	f(*int) *int
112}
113
114type P struct {
115	x int
116}
117
118func (p *P) f(pi *int) *int {
119	print(p)  // @pointsto p@i5p:6
120	print(pi) // @pointsto i@i5i:6
121	return &p.x
122}
123
124func interface5() {
125	var p P // @line i5p
126	var j J = &p
127	var i int      // @line i5i
128	print(j.f(&i)) // @pointsto p.x@i5p:6
129	print(&i)      // @pointsto i@i5i:6
130
131	print(j) // @pointsto makeinterface:*main.P
132}
133
134// @calls main.interface5 -> (*main.P).f
135
136func interface6() {
137	f := I.f
138	print(f) // @pointsto (main.I).f$thunk
139	f(new(struct{ D }))
140}
141
142// @calls main.interface6 -> (main.I).f$thunk
143// @calls (main.I).f$thunk -> (*struct{main.D}).f
144
145func main() {
146	interface1()
147	interface2()
148	interface3()
149	interface4()
150	interface5()
151	interface6()
152}
153