1 | // Copyright 2012 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | // This file contains tests for the loopclosure checker. |
6 | |
7 | package testdata |
8 | |
9 | import ( |
10 | "sync" |
11 | |
12 | "golang.org/x/sync/errgroup" |
13 | ) |
14 | |
15 | var A int |
16 | |
17 | func _() { |
18 | var s []int |
19 | for i, v := range s { |
20 | go func() { |
21 | println(i) // want "loop variable i captured by func literal" |
22 | println(v) // want "loop variable v captured by func literal" |
23 | }() |
24 | } |
25 | for i, v := range s { |
26 | defer func() { |
27 | println(i) // want "loop variable i captured by func literal" |
28 | println(v) // want "loop variable v captured by func literal" |
29 | }() |
30 | } |
31 | for i := range s { |
32 | go func() { |
33 | println(i) // want "loop variable i captured by func literal" |
34 | }() |
35 | } |
36 | for _, v := range s { |
37 | go func() { |
38 | println(v) // want "loop variable v captured by func literal" |
39 | }() |
40 | } |
41 | for i, v := range s { |
42 | go func() { |
43 | println(i, v) |
44 | }() |
45 | println("unfortunately, we don't catch the error above because of this statement") |
46 | } |
47 | for i, v := range s { |
48 | go func(i, v int) { |
49 | println(i, v) |
50 | }(i, v) |
51 | } |
52 | for i, v := range s { |
53 | i, v := i, v |
54 | go func() { |
55 | println(i, v) |
56 | }() |
57 | } |
58 | |
59 | // iteration variable declared outside the loop |
60 | for A = range s { |
61 | go func() { |
62 | println(A) // want "loop variable A captured by func literal" |
63 | }() |
64 | } |
65 | // iteration variable declared in a different file |
66 | for B = range s { |
67 | go func() { |
68 | println(B) // want "loop variable B captured by func literal" |
69 | }() |
70 | } |
71 | // If the key of the range statement is not an identifier |
72 | // the code should not panic (it used to). |
73 | var x [2]int |
74 | var f int |
75 | for x[0], f = range s { |
76 | go func() { |
77 | _ = f // want "loop variable f captured by func literal" |
78 | }() |
79 | } |
80 | type T struct { |
81 | v int |
82 | } |
83 | for _, v := range s { |
84 | go func() { |
85 | _ = T{v: 1} |
86 | _ = map[int]int{v: 1} // want "loop variable v captured by func literal" |
87 | }() |
88 | } |
89 | |
90 | // ordinary for-loops |
91 | for i := 0; i < 10; i++ { |
92 | go func() { |
93 | print(i) // want "loop variable i captured by func literal" |
94 | }() |
95 | } |
96 | for i, j := 0, 1; i < 100; i, j = j, i+j { |
97 | go func() { |
98 | print(j) // want "loop variable j captured by func literal" |
99 | }() |
100 | } |
101 | type cons struct { |
102 | car int |
103 | cdr *cons |
104 | } |
105 | var head *cons |
106 | for p := head; p != nil; p = p.cdr { |
107 | go func() { |
108 | print(p.car) // want "loop variable p captured by func literal" |
109 | }() |
110 | } |
111 | } |
112 | |
113 | // Cases that rely on recursively checking for last statements. |
114 | func _() { |
115 | |
116 | for i := range "outer" { |
117 | for j := range "inner" { |
118 | if j < 1 { |
119 | defer func() { |
120 | print(i) // want "loop variable i captured by func literal" |
121 | }() |
122 | } else if j < 2 { |
123 | go func() { |
124 | print(i) // want "loop variable i captured by func literal" |
125 | }() |
126 | } else { |
127 | go func() { |
128 | print(i) |
129 | }() |
130 | println("we don't catch the error above because of this statement") |
131 | } |
132 | } |
133 | } |
134 | |
135 | for i := 0; i < 10; i++ { |
136 | for j := 0; j < 10; j++ { |
137 | if j < 1 { |
138 | switch j { |
139 | case 0: |
140 | defer func() { |
141 | print(i) // want "loop variable i captured by func literal" |
142 | }() |
143 | default: |
144 | go func() { |
145 | print(i) // want "loop variable i captured by func literal" |
146 | }() |
147 | } |
148 | } else if j < 2 { |
149 | var a interface{} = j |
150 | switch a.(type) { |
151 | case int: |
152 | defer func() { |
153 | print(i) // want "loop variable i captured by func literal" |
154 | }() |
155 | default: |
156 | go func() { |
157 | print(i) // want "loop variable i captured by func literal" |
158 | }() |
159 | } |
160 | } else { |
161 | ch := make(chan string) |
162 | select { |
163 | case <-ch: |
164 | defer func() { |
165 | print(i) // want "loop variable i captured by func literal" |
166 | }() |
167 | default: |
168 | go func() { |
169 | print(i) // want "loop variable i captured by func literal" |
170 | }() |
171 | } |
172 | } |
173 | } |
174 | } |
175 | } |
176 | |
177 | // Group is used to test that loopclosure only matches Group.Go when Group is |
178 | // from the golang.org/x/sync/errgroup package. |
179 | type Group struct{} |
180 | |
181 | func (g *Group) Go(func() error) {} |
182 | |
183 | func _() { |
184 | var s []int |
185 | // errgroup.Group.Go() invokes Go routines |
186 | g := new(errgroup.Group) |
187 | for i, v := range s { |
188 | g.Go(func() error { |
189 | print(i) // want "loop variable i captured by func literal" |
190 | print(v) // want "loop variable v captured by func literal" |
191 | return nil |
192 | }) |
193 | } |
194 | |
195 | for i, v := range s { |
196 | if i > 0 { |
197 | g.Go(func() error { |
198 | print(i) // want "loop variable i captured by func literal" |
199 | return nil |
200 | }) |
201 | } else { |
202 | g.Go(func() error { |
203 | print(v) // want "loop variable v captured by func literal" |
204 | return nil |
205 | }) |
206 | } |
207 | } |
208 | |
209 | // Do not match other Group.Go cases |
210 | g1 := new(Group) |
211 | for i, v := range s { |
212 | g1.Go(func() error { |
213 | print(i) |
214 | print(v) |
215 | return nil |
216 | }) |
217 | } |
218 | } |
219 | |
220 | // Real-world example from #16520, slightly simplified |
221 | func _() { |
222 | var nodes []interface{} |
223 | |
224 | critical := new(errgroup.Group) |
225 | others := sync.WaitGroup{} |
226 | |
227 | isCritical := func(node interface{}) bool { return false } |
228 | run := func(node interface{}) error { return nil } |
229 | |
230 | for _, node := range nodes { |
231 | if isCritical(node) { |
232 | critical.Go(func() error { |
233 | return run(node) // want "loop variable node captured by func literal" |
234 | }) |
235 | } else { |
236 | others.Add(1) |
237 | go func() { |
238 | _ = run(node) // want "loop variable node captured by func literal" |
239 | others.Done() |
240 | }() |
241 | } |
242 | } |
243 | } |
244 |
Members