reflect.go
4.2 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
// +build ignore
package main
import "reflect"
import "unsafe"
var a, b int
var unknown bool
func reflectIndirect() {
ptr := &a
// Pointer:
print(reflect.Indirect(reflect.ValueOf(&ptr)).Interface().(*int)) // @pointsto main.a
// Non-pointer:
print(reflect.Indirect(reflect.ValueOf([]*int{ptr})).Interface().([]*int)[0]) // @pointsto main.a
}
func reflectNewAt() {
var x [8]byte
print(reflect.NewAt(reflect.TypeOf(3), unsafe.Pointer(&x)).Interface()) // @types *int
}
// @warning "unsound: main.reflectNewAt contains a reflect.NewAt.. call"
func reflectTypeOf() {
t := reflect.TypeOf(3)
if unknown {
t = reflect.TypeOf("foo")
}
// TODO(adonovan): make types.Eval let us refer to unexported types.
print(t) // #@types *reflect.rtype
print(reflect.Zero(t).Interface()) // @types int | string
newint := reflect.New(t).Interface() // @line rtonew
print(newint) // @types *int | *string
print(newint.(*int)) // @pointsto <alloc in reflect.New>
print(newint.(*string)) // @pointsto <alloc in reflect.New>
}
func reflectTypeElem() {
print(reflect.Zero(reflect.TypeOf(&a).Elem()).Interface()) // @types int
print(reflect.Zero(reflect.TypeOf([]string{}).Elem()).Interface()) // @types string
print(reflect.Zero(reflect.TypeOf(make(chan bool)).Elem()).Interface()) // @types bool
print(reflect.Zero(reflect.TypeOf(make(map[string]float64)).Elem()).Interface()) // @types float64
print(reflect.Zero(reflect.TypeOf([3]complex64{}).Elem()).Interface()) // @types complex64
print(reflect.Zero(reflect.TypeOf(3).Elem()).Interface()) // @types
print(reflect.Zero(reflect.TypeOf(new(interface{})).Elem())) // @types interface{}
print(reflect.Zero(reflect.TypeOf(new(interface{})).Elem()).Interface()) // @types
}
// reflect.Values within reflect.Values.
func metareflection() {
// "box" a *int twice, unbox it twice.
v0 := reflect.ValueOf(&a)
print(v0) // @types *int
v1 := reflect.ValueOf(v0) // box
print(v1) // @types reflect.Value
v2 := reflect.ValueOf(v1) // box
print(v2) // @types reflect.Value
v1a := v2.Interface().(reflect.Value) // unbox
print(v1a) // @types reflect.Value
v0a := v1a.Interface().(reflect.Value) // unbox
print(v0a) // @types *int
print(v0a.Interface().(*int)) // @pointsto main.a
// "box" an interface{} lvalue twice, unbox it twice.
var iface interface{} = 3
x0 := reflect.ValueOf(&iface).Elem()
print(x0) // @types interface{}
x1 := reflect.ValueOf(x0) // box
print(x1) // @types reflect.Value
x2 := reflect.ValueOf(x1) // box
print(x2) // @types reflect.Value
x1a := x2.Interface().(reflect.Value) // unbox
print(x1a) // @types reflect.Value
x0a := x1a.Interface().(reflect.Value) // unbox
print(x0a) // @types interface{}
print(x0a.Interface()) // @types int
}
type T struct{}
// When the output of a type constructor flows to its input, we must
// bound the set of types created to ensure termination of the algorithm.
func typeCycle() {
t := reflect.TypeOf(0)
u := reflect.TypeOf("")
v := reflect.TypeOf(T{})
for unknown {
t = reflect.PtrTo(t)
t = reflect.SliceOf(t)
u = reflect.SliceOf(u)
if unknown {
v = reflect.ChanOf(reflect.BothDir, v)
} else {
v = reflect.PtrTo(v)
}
}
// Type height is bounded to about 4 map/slice/chan/pointer constructors.
print(reflect.Zero(t).Interface()) // @types int | []*int | []*[]*int
print(reflect.Zero(u).Interface()) // @types string | []string | [][]string | [][][]string | [][][][]string
print(reflect.Zero(v).Interface()) // @types T | *T | **T | ***T | ****T | chan T | *chan T | **chan T | chan *T | *chan *T | chan **T | chan ***T | chan chan T | chan *chan T | chan chan *T
}
func main() {
reflectIndirect()
reflectNewAt()
reflectTypeOf()
reflectTypeElem()
metareflection()
typeCycle()
}