1// +build ignore
2
3package main
4
5import "reflect"
6import "unsafe"
7
8var a, b int
9var unknown bool
10
11func reflectIndirect() {
12	ptr := &a
13	// Pointer:
14	print(reflect.Indirect(reflect.ValueOf(&ptr)).Interface().(*int)) // @pointsto main.a
15	// Non-pointer:
16	print(reflect.Indirect(reflect.ValueOf([]*int{ptr})).Interface().([]*int)[0]) // @pointsto main.a
17}
18
19func reflectNewAt() {
20	var x [8]byte
21	print(reflect.NewAt(reflect.TypeOf(3), unsafe.Pointer(&x)).Interface()) // @types *int
22}
23
24// @warning "unsound: main.reflectNewAt contains a reflect.NewAt.. call"
25
26func reflectTypeOf() {
27	t := reflect.TypeOf(3)
28	if unknown {
29		t = reflect.TypeOf("foo")
30	}
31	// TODO(adonovan): make types.Eval let us refer to unexported types.
32	print(t)                             // #@types *reflect.rtype
33	print(reflect.Zero(t).Interface())   // @types int | string
34	newint := reflect.New(t).Interface() // @line rtonew
35	print(newint)                        // @types *int | *string
36	print(newint.(*int))                 // @pointsto <alloc in reflect.New>
37	print(newint.(*string))              // @pointsto <alloc in reflect.New>
38}
39
40func reflectTypeElem() {
41	print(reflect.Zero(reflect.TypeOf(&a).Elem()).Interface())                       // @types int
42	print(reflect.Zero(reflect.TypeOf([]string{}).Elem()).Interface())               // @types string
43	print(reflect.Zero(reflect.TypeOf(make(chan bool)).Elem()).Interface())          // @types bool
44	print(reflect.Zero(reflect.TypeOf(make(map[string]float64)).Elem()).Interface()) // @types float64
45	print(reflect.Zero(reflect.TypeOf([3]complex64{}).Elem()).Interface())           // @types complex64
46	print(reflect.Zero(reflect.TypeOf(3).Elem()).Interface())                        // @types
47	print(reflect.Zero(reflect.TypeOf(new(interface{})).Elem()))                     // @types interface{}
48	print(reflect.Zero(reflect.TypeOf(new(interface{})).Elem()).Interface())         // @types
49}
50
51// reflect.Values within reflect.Values.
52func metareflection() {
53	// "box" a *int twice, unbox it twice.
54	v0 := reflect.ValueOf(&a)
55	print(v0)                              // @types *int
56	v1 := reflect.ValueOf(v0)              // box
57	print(v1)                              // @types reflect.Value
58	v2 := reflect.ValueOf(v1)              // box
59	print(v2)                              // @types reflect.Value
60	v1a := v2.Interface().(reflect.Value)  // unbox
61	print(v1a)                             // @types reflect.Value
62	v0a := v1a.Interface().(reflect.Value) // unbox
63	print(v0a)                             // @types *int
64	print(v0a.Interface().(*int))          // @pointsto main.a
65
66	// "box" an interface{} lvalue twice, unbox it twice.
67	var iface interface{} = 3
68	x0 := reflect.ValueOf(&iface).Elem()
69	print(x0)                              // @types interface{}
70	x1 := reflect.ValueOf(x0)              // box
71	print(x1)                              // @types reflect.Value
72	x2 := reflect.ValueOf(x1)              // box
73	print(x2)                              // @types reflect.Value
74	x1a := x2.Interface().(reflect.Value)  // unbox
75	print(x1a)                             // @types reflect.Value
76	x0a := x1a.Interface().(reflect.Value) // unbox
77	print(x0a)                             // @types interface{}
78	print(x0a.Interface())                 // @types int
79}
80
81type T struct{}
82
83// When the output of a type constructor flows to its input, we must
84// bound the set of types created to ensure termination of the algorithm.
85func typeCycle() {
86	t := reflect.TypeOf(0)
87	u := reflect.TypeOf("")
88	v := reflect.TypeOf(T{})
89	for unknown {
90		t = reflect.PtrTo(t)
91		t = reflect.SliceOf(t)
92
93		u = reflect.SliceOf(u)
94
95		if unknown {
96			v = reflect.ChanOf(reflect.BothDir, v)
97		} else {
98			v = reflect.PtrTo(v)
99		}
100	}
101
102	// Type height is bounded to about 4 map/slice/chan/pointer constructors.
103	print(reflect.Zero(t).Interface()) // @types int | []*int | []*[]*int
104	print(reflect.Zero(u).Interface()) // @types string | []string | [][]string | [][][]string | [][][][]string
105	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
106}
107
108func main() {
109	reflectIndirect()
110	reflectNewAt()
111	reflectTypeOf()
112	reflectTypeElem()
113	metareflection()
114	typeCycle()
115}
116