1 | // Tests of bound method closures. |
---|---|
2 | |
3 | package main |
4 | |
5 | import ( |
6 | "errors" |
7 | "fmt" |
8 | ) |
9 | |
10 | func assert(b bool) { |
11 | if !b { |
12 | panic("oops") |
13 | } |
14 | } |
15 | |
16 | type I int |
17 | |
18 | func (i I) add(x int) int { |
19 | return int(i) + x |
20 | } |
21 | |
22 | func valueReceiver() { |
23 | var three I = 3 |
24 | assert(three.add(5) == 8) |
25 | var add3 func(int) int = three.add |
26 | assert(add3(5) == 8) |
27 | } |
28 | |
29 | type S struct{ x int } |
30 | |
31 | func (s *S) incr() { |
32 | s.x++ |
33 | } |
34 | |
35 | func (s *S) get() int { |
36 | return s.x |
37 | } |
38 | |
39 | func pointerReceiver() { |
40 | ps := new(S) |
41 | incr := ps.incr |
42 | get := ps.get |
43 | assert(get() == 0) |
44 | incr() |
45 | incr() |
46 | incr() |
47 | assert(get() == 3) |
48 | } |
49 | |
50 | func addressibleValuePointerReceiver() { |
51 | var s S |
52 | incr := s.incr |
53 | get := s.get |
54 | assert(get() == 0) |
55 | incr() |
56 | incr() |
57 | incr() |
58 | assert(get() == 3) |
59 | } |
60 | |
61 | type S2 struct { |
62 | S |
63 | } |
64 | |
65 | func promotedReceiver() { |
66 | var s2 S2 |
67 | incr := s2.incr |
68 | get := s2.get |
69 | assert(get() == 0) |
70 | incr() |
71 | incr() |
72 | incr() |
73 | assert(get() == 3) |
74 | } |
75 | |
76 | func anonStruct() { |
77 | var s struct{ S } |
78 | incr := s.incr |
79 | get := s.get |
80 | assert(get() == 0) |
81 | incr() |
82 | incr() |
83 | incr() |
84 | assert(get() == 3) |
85 | } |
86 | |
87 | func typeCheck() { |
88 | var i interface{} |
89 | i = (*S).incr |
90 | _ = i.(func(*S)) // type assertion: receiver type prepended to params |
91 | |
92 | var s S |
93 | i = s.incr |
94 | _ = i.(func()) // type assertion: receiver type disappears |
95 | } |
96 | |
97 | type errString string |
98 | |
99 | func (err errString) Error() string { |
100 | return string(err) |
101 | } |
102 | |
103 | // Regression test for a builder crash. |
104 | func regress1(x error) func() string { |
105 | return x.Error |
106 | } |
107 | |
108 | // Regression test for b/7269: |
109 | // taking the value of an interface method performs a nil check. |
110 | func nilInterfaceMethodValue() { |
111 | err := errors.New("ok") |
112 | f := err.Error |
113 | if got := f(); got != "ok" { |
114 | panic(got) |
115 | } |
116 | |
117 | err = nil |
118 | if got := f(); got != "ok" { |
119 | panic(got) |
120 | } |
121 | |
122 | defer func() { |
123 | r := fmt.Sprint(recover()) |
124 | // runtime panic string varies across toolchains |
125 | if r != "interface conversion: interface is nil, not error" && |
126 | r != "runtime error: invalid memory address or nil pointer dereference" && |
127 | r != "method value: interface is nil" { |
128 | panic("want runtime panic from nil interface method value, got " + r) |
129 | } |
130 | }() |
131 | f = err.Error // runtime panic: err is nil |
132 | panic("unreachable") |
133 | } |
134 | |
135 | func main() { |
136 | valueReceiver() |
137 | pointerReceiver() |
138 | addressibleValuePointerReceiver() |
139 | promotedReceiver() |
140 | anonStruct() |
141 | typeCheck() |
142 | |
143 | if e := regress1(errString("hi"))(); e != "hi" { |
144 | panic(e) |
145 | } |
146 | |
147 | nilInterfaceMethodValue() |
148 | } |
149 |
Members