]>
Commit | Line | Data |
---|---|---|
487cf647 FG |
1 | #![allow(unused_braces, unused_variables, dead_code)] |
2 | #![allow( | |
3 | clippy::collapsible_else_if, | |
4 | clippy::unused_unit, | |
5 | clippy::let_unit_value, | |
6 | clippy::match_single_binding, | |
fe692bf9 FG |
7 | clippy::never_loop, |
8 | clippy::needless_if | |
487cf647 FG |
9 | )] |
10 | #![warn(clippy::manual_let_else)] | |
781aab86 | 11 | //@no-rustfix |
49aad941 FG |
12 | enum Variant { |
13 | A(usize, usize), | |
14 | B(usize), | |
15 | C, | |
16 | } | |
17 | ||
487cf647 FG |
18 | fn g() -> Option<()> { |
19 | None | |
20 | } | |
21 | ||
22 | fn main() {} | |
23 | ||
24 | fn fire() { | |
25 | let v = if let Some(v_some) = g() { v_some } else { return }; | |
781aab86 FG |
26 | //~^ ERROR: this could be rewritten as `let...else` |
27 | //~| NOTE: `-D clippy::manual-let-else` implied by `-D warnings` | |
487cf647 | 28 | let v = if let Some(v_some) = g() { |
781aab86 | 29 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
30 | v_some |
31 | } else { | |
32 | return; | |
33 | }; | |
34 | ||
35 | let v = if let Some(v) = g() { | |
781aab86 | 36 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
37 | // Blocks around the identity should have no impact |
38 | { | |
39 | { v } | |
40 | } | |
41 | } else { | |
42 | // Some computation should still make it fire | |
43 | g(); | |
44 | return; | |
45 | }; | |
46 | ||
47 | // continue and break diverge | |
48 | loop { | |
49 | let v = if let Some(v_some) = g() { v_some } else { continue }; | |
781aab86 | 50 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 | 51 | let v = if let Some(v_some) = g() { v_some } else { break }; |
781aab86 | 52 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
53 | } |
54 | ||
55 | // panic also diverges | |
56 | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | |
781aab86 | 57 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
58 | |
59 | // abort also diverges | |
60 | let v = if let Some(v_some) = g() { | |
781aab86 | 61 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
62 | v_some |
63 | } else { | |
64 | std::process::abort() | |
65 | }; | |
66 | ||
67 | // If whose two branches diverge also diverges | |
68 | let v = if let Some(v_some) = g() { | |
781aab86 | 69 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
70 | v_some |
71 | } else { | |
72 | if true { return } else { panic!() } | |
73 | }; | |
74 | ||
75 | // Diverging after an if still makes the block diverge: | |
76 | let v = if let Some(v_some) = g() { | |
781aab86 | 77 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
78 | v_some |
79 | } else { | |
80 | if true {} | |
81 | panic!(); | |
82 | }; | |
83 | ||
84 | // A match diverges if all branches diverge: | |
85 | // Note: the corresponding let-else requires a ; at the end of the match | |
86 | // as otherwise the type checker does not turn it into a ! type. | |
87 | let v = if let Some(v_some) = g() { | |
781aab86 | 88 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
89 | v_some |
90 | } else { | |
91 | match () { | |
92 | _ if panic!() => {}, | |
93 | _ => panic!(), | |
94 | } | |
95 | }; | |
96 | ||
97 | // An if's expression can cause divergence: | |
98 | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; | |
781aab86 | 99 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
100 | |
101 | // An expression of a match can cause divergence: | |
102 | let v = if let Some(v_some) = g() { | |
781aab86 | 103 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
104 | v_some |
105 | } else { | |
106 | match panic!() { | |
107 | _ => {}, | |
108 | } | |
109 | }; | |
110 | ||
111 | // Top level else if | |
112 | let v = if let Some(v_some) = g() { | |
781aab86 | 113 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
114 | v_some |
115 | } else if true { | |
116 | return; | |
117 | } else { | |
118 | panic!("diverge"); | |
119 | }; | |
120 | ||
121 | // All match arms diverge | |
122 | let v = if let Some(v_some) = g() { | |
781aab86 | 123 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
124 | v_some |
125 | } else { | |
126 | match (g(), g()) { | |
127 | (Some(_), None) => return, | |
128 | (None, Some(_)) => { | |
129 | if true { | |
130 | return; | |
131 | } else { | |
132 | panic!(); | |
133 | } | |
134 | }, | |
135 | _ => return, | |
136 | } | |
137 | }; | |
138 | ||
139 | // Tuples supported for the declared variables | |
140 | let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { | |
781aab86 | 141 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
142 | v_some |
143 | } else { | |
144 | return; | |
145 | }; | |
146 | ||
fe692bf9 FG |
147 | // Tuples supported with multiple bindings |
148 | let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { | |
781aab86 | 149 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
150 | (w_some, v_some) |
151 | } else { | |
152 | return; | |
153 | }; | |
154 | ||
155 | // entirely inside macro lints | |
156 | macro_rules! create_binding_if_some { | |
157 | ($n:ident, $e:expr) => { | |
158 | let $n = if let Some(v) = $e { v } else { return }; | |
159 | }; | |
160 | } | |
161 | create_binding_if_some!(w, g()); | |
49aad941 FG |
162 | |
163 | fn e() -> Variant { | |
164 | Variant::A(0, 0) | |
165 | } | |
166 | ||
49aad941 | 167 | let v = if let Variant::A(a, 0) = e() { a } else { return }; |
781aab86 | 168 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
169 | |
170 | // `mut v` is inserted into the pattern | |
171 | let mut v = if let Variant::B(b) = e() { b } else { return }; | |
781aab86 | 172 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
173 | |
174 | // Nesting works | |
175 | let nested = Ok(Some(e())); | |
176 | let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { | |
781aab86 | 177 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
178 | b |
179 | } else { | |
180 | return; | |
181 | }; | |
182 | // dot dot works | |
183 | let v = if let Variant::A(.., a) = e() { a } else { return }; | |
781aab86 | 184 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
185 | |
186 | // () is preserved: a bit of an edge case but make sure it stays around | |
187 | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; | |
781aab86 | 188 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
189 | |
190 | // Tuple structs work | |
191 | let w = if let Some(S { v: x }) = Some(S { v: 0 }) { | |
781aab86 | 192 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
193 | x |
194 | } else { | |
195 | return; | |
196 | }; | |
197 | ||
198 | // Field init shorthand is suggested | |
199 | let v = if let Some(S { v: x }) = Some(S { v: 0 }) { | |
781aab86 | 200 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
201 | x |
202 | } else { | |
203 | return; | |
204 | }; | |
205 | ||
206 | // Multi-field structs also work | |
207 | let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> { | |
781aab86 | 208 | //~^ ERROR: this could be rewritten as `let...else` |
fe692bf9 FG |
209 | (x, v, w) |
210 | } else { | |
211 | return; | |
212 | }; | |
487cf647 FG |
213 | } |
214 | ||
215 | fn not_fire() { | |
216 | let v = if let Some(v_some) = g() { | |
217 | // Nothing returned. Should not fire. | |
218 | } else { | |
219 | return; | |
220 | }; | |
221 | ||
222 | let w = 0; | |
223 | let v = if let Some(v_some) = g() { | |
224 | // Different variable than v_some. Should not fire. | |
225 | w | |
226 | } else { | |
227 | return; | |
228 | }; | |
229 | ||
230 | let v = if let Some(v_some) = g() { | |
231 | // Computation in then clause. Should not fire. | |
232 | g(); | |
233 | v_some | |
234 | } else { | |
235 | return; | |
236 | }; | |
237 | ||
238 | let v = if let Some(v_some) = g() { | |
239 | v_some | |
240 | } else { | |
241 | if false { | |
242 | return; | |
243 | } | |
244 | // This doesn't diverge. Should not fire. | |
245 | () | |
246 | }; | |
247 | ||
248 | let v = if let Some(v_some) = g() { | |
249 | v_some | |
250 | } else { | |
251 | // There is one match arm that doesn't diverge. Should not fire. | |
252 | match (g(), g()) { | |
253 | (Some(_), None) => return, | |
254 | (None, Some(_)) => return, | |
255 | (Some(_), Some(_)) => (), | |
256 | _ => return, | |
257 | } | |
258 | }; | |
259 | ||
260 | let v = if let Some(v_some) = g() { | |
261 | v_some | |
262 | } else { | |
263 | // loop with a break statement inside does not diverge. | |
264 | loop { | |
265 | break; | |
266 | } | |
267 | }; | |
268 | ||
269 | enum Uninhabited {} | |
270 | fn un() -> Uninhabited { | |
271 | panic!() | |
272 | } | |
273 | let v = if let Some(v_some) = None { | |
274 | v_some | |
275 | } else { | |
276 | // Don't lint if the type is uninhabited but not ! | |
277 | un() | |
278 | }; | |
279 | ||
280 | fn question_mark() -> Option<()> { | |
281 | let v = if let Some(v) = g() { | |
282 | v | |
283 | } else { | |
284 | // Question mark does not diverge | |
285 | g()? | |
286 | }; | |
287 | Some(v) | |
288 | } | |
289 | ||
290 | // Macro boundary inside let | |
291 | macro_rules! some_or_return { | |
292 | ($e:expr) => { | |
293 | if let Some(v) = $e { v } else { return } | |
294 | }; | |
295 | } | |
296 | let v = some_or_return!(g()); | |
297 | ||
298 | // Also macro boundary inside let, but inside a macro | |
299 | macro_rules! create_binding_if_some_nf { | |
300 | ($n:ident, $e:expr) => { | |
301 | let $n = some_or_return!($e); | |
302 | }; | |
303 | } | |
304 | create_binding_if_some_nf!(v, g()); | |
305 | ||
306 | // Already a let-else | |
add651ee FG |
307 | let Some(a) = (if let Some(b) = Some(Some(())) { b } else { return }) else { |
308 | panic!() | |
309 | }; | |
487cf647 FG |
310 | |
311 | // If a type annotation is present, don't lint as | |
312 | // expressing the type might be too hard | |
313 | let v: () = if let Some(v_some) = g() { v_some } else { panic!() }; | |
314 | ||
315 | // Issue 9940 | |
316 | // Suggestion should not expand macros | |
317 | macro_rules! macro_call { | |
318 | () => { | |
319 | return () | |
320 | }; | |
321 | } | |
322 | ||
323 | let ff = Some(1); | |
324 | let _ = match ff { | |
781aab86 | 325 | //~^ ERROR: this could be rewritten as `let...else` |
487cf647 FG |
326 | Some(value) => value, |
327 | _ => macro_call!(), | |
328 | }; | |
9ffffee4 FG |
329 | |
330 | // Issue 10296 | |
331 | // The let/else block in the else part is not divergent despite the presence of return | |
332 | let _x = if let Some(x) = Some(1) { | |
333 | x | |
334 | } else { | |
add651ee | 335 | let Some(_z) = Some(3) else { return }; |
9ffffee4 FG |
336 | 1 |
337 | }; | |
fe692bf9 FG |
338 | |
339 | // This would require creation of a suggestion of the form | |
340 | // let v @ (Some(_), _) = (...) else { return }; | |
341 | // Which is too advanced for our code, so we just bail. | |
342 | let v = if let (Some(v_some), w_some) = (g(), 0) { | |
343 | (w_some, v_some) | |
344 | } else { | |
345 | return; | |
346 | }; | |
347 | } | |
348 | ||
349 | struct S<T> { | |
350 | v: T, | |
351 | } | |
352 | ||
353 | struct U<T> { | |
354 | v: T, | |
355 | w: T, | |
356 | x: T, | |
487cf647 | 357 | } |