interfaces.go
2.61 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// +build ignore
package main
type I interface {
f()
}
type C int
func (*C) f() {}
type D struct{ ptr *int }
func (D) f() {}
type E struct{}
func (*E) f() {}
var a, b int
var unknown bool // defeat dead-code elimination
func interface1() {
var i interface{} = &a
var j interface{} = D{&b}
k := j
if unknown {
k = i
}
print(i) // @types *int
print(j) // @types D
print(k) // @types *int | D
print(i.(*int)) // @pointsto main.a
print(j.(*int)) // @pointsto
print(k.(*int)) // @pointsto main.a
print(i.(D).ptr) // @pointsto
print(j.(D).ptr) // @pointsto main.b
print(k.(D).ptr) // @pointsto main.b
}
func interface2() {
var i I = (*C)(&a)
var j I = D{&a}
k := j
if unknown {
k = i
}
print(i) // @types *C
print(j) // @types D
print(k) // @types *C | D
print(k) // @pointsto makeinterface:main.D | makeinterface:*main.C
k.f()
// @calls main.interface2 -> (*main.C).f
// @calls main.interface2 -> (main.D).f
print(i.(*C)) // @pointsto main.a
print(j.(D).ptr) // @pointsto main.a
print(k.(*C)) // @pointsto main.a
switch x := k.(type) {
case *C:
print(x) // @pointsto main.a
case D:
print(x.ptr) // @pointsto main.a
case *E:
print(x) // @pointsto
}
}
func interface3() {
// There should be no backflow of concrete types from the type-switch to x.
var x interface{} = 0
print(x) // @types int
switch x.(type) {
case int:
case string:
}
}
func interface4() {
var i interface{} = D{&a}
if unknown {
i = 123
}
print(i) // @types int | D
j := i.(I) // interface narrowing type-assertion
print(j) // @types D
print(j.(D).ptr) // @pointsto main.a
var l interface{} = j // interface widening assignment.
print(l) // @types D
print(l.(D).ptr) // @pointsto main.a
m := j.(interface{}) // interface widening type-assertion.
print(m) // @types D
print(m.(D).ptr) // @pointsto main.a
}
// Interface method calls and value flow:
type J interface {
f(*int) *int
}
type P struct {
x int
}
func (p *P) f(pi *int) *int {
print(p) // @pointsto p@i5p:6
print(pi) // @pointsto i@i5i:6
return &p.x
}
func interface5() {
var p P // @line i5p
var j J = &p
var i int // @line i5i
print(j.f(&i)) // @pointsto p.x@i5p:6
print(&i) // @pointsto i@i5i:6
print(j) // @pointsto makeinterface:*main.P
}
// @calls main.interface5 -> (*main.P).f
func interface6() {
f := I.f
print(f) // @pointsto (main.I).f$thunk
f(new(struct{ D }))
}
// @calls main.interface6 -> (main.I).f$thunk
// @calls (main.I).f$thunk -> (*struct{main.D}).f
func main() {
interface1()
interface2()
interface3()
interface4()
interface5()
interface6()
}