]>
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, | |
7 | clippy::never_loop | |
8 | )] | |
9 | #![warn(clippy::manual_let_else)] | |
10 | ||
11 | fn g() -> Option<()> { | |
12 | None | |
13 | } | |
14 | ||
15 | fn main() {} | |
16 | ||
17 | fn fire() { | |
18 | let v = if let Some(v_some) = g() { v_some } else { return }; | |
19 | let v = if let Some(v_some) = g() { | |
20 | v_some | |
21 | } else { | |
22 | return; | |
23 | }; | |
24 | ||
25 | let v = if let Some(v) = g() { | |
26 | // Blocks around the identity should have no impact | |
27 | { | |
28 | { v } | |
29 | } | |
30 | } else { | |
31 | // Some computation should still make it fire | |
32 | g(); | |
33 | return; | |
34 | }; | |
35 | ||
36 | // continue and break diverge | |
37 | loop { | |
38 | let v = if let Some(v_some) = g() { v_some } else { continue }; | |
39 | let v = if let Some(v_some) = g() { v_some } else { break }; | |
40 | } | |
41 | ||
42 | // panic also diverges | |
43 | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | |
44 | ||
45 | // abort also diverges | |
46 | let v = if let Some(v_some) = g() { | |
47 | v_some | |
48 | } else { | |
49 | std::process::abort() | |
50 | }; | |
51 | ||
52 | // If whose two branches diverge also diverges | |
53 | let v = if let Some(v_some) = g() { | |
54 | v_some | |
55 | } else { | |
56 | if true { return } else { panic!() } | |
57 | }; | |
58 | ||
59 | // Diverging after an if still makes the block diverge: | |
60 | let v = if let Some(v_some) = g() { | |
61 | v_some | |
62 | } else { | |
63 | if true {} | |
64 | panic!(); | |
65 | }; | |
66 | ||
67 | // A match diverges if all branches diverge: | |
68 | // Note: the corresponding let-else requires a ; at the end of the match | |
69 | // as otherwise the type checker does not turn it into a ! type. | |
70 | let v = if let Some(v_some) = g() { | |
71 | v_some | |
72 | } else { | |
73 | match () { | |
74 | _ if panic!() => {}, | |
75 | _ => panic!(), | |
76 | } | |
77 | }; | |
78 | ||
79 | // An if's expression can cause divergence: | |
80 | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; | |
81 | ||
82 | // An expression of a match can cause divergence: | |
83 | let v = if let Some(v_some) = g() { | |
84 | v_some | |
85 | } else { | |
86 | match panic!() { | |
87 | _ => {}, | |
88 | } | |
89 | }; | |
90 | ||
91 | // Top level else if | |
92 | let v = if let Some(v_some) = g() { | |
93 | v_some | |
94 | } else if true { | |
95 | return; | |
96 | } else { | |
97 | panic!("diverge"); | |
98 | }; | |
99 | ||
100 | // All match arms diverge | |
101 | let v = if let Some(v_some) = g() { | |
102 | v_some | |
103 | } else { | |
104 | match (g(), g()) { | |
105 | (Some(_), None) => return, | |
106 | (None, Some(_)) => { | |
107 | if true { | |
108 | return; | |
109 | } else { | |
110 | panic!(); | |
111 | } | |
112 | }, | |
113 | _ => return, | |
114 | } | |
115 | }; | |
116 | ||
117 | // Tuples supported for the declared variables | |
118 | let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { | |
119 | v_some | |
120 | } else { | |
121 | return; | |
122 | }; | |
123 | ||
124 | // Tuples supported for the identity block and pattern | |
125 | let v = if let (Some(v_some), w_some) = (g(), 0) { | |
126 | (w_some, v_some) | |
127 | } else { | |
128 | return; | |
129 | }; | |
130 | ||
131 | // entirely inside macro lints | |
132 | macro_rules! create_binding_if_some { | |
133 | ($n:ident, $e:expr) => { | |
134 | let $n = if let Some(v) = $e { v } else { return }; | |
135 | }; | |
136 | } | |
137 | create_binding_if_some!(w, g()); | |
138 | } | |
139 | ||
140 | fn not_fire() { | |
141 | let v = if let Some(v_some) = g() { | |
142 | // Nothing returned. Should not fire. | |
143 | } else { | |
144 | return; | |
145 | }; | |
146 | ||
147 | let w = 0; | |
148 | let v = if let Some(v_some) = g() { | |
149 | // Different variable than v_some. Should not fire. | |
150 | w | |
151 | } else { | |
152 | return; | |
153 | }; | |
154 | ||
155 | let v = if let Some(v_some) = g() { | |
156 | // Computation in then clause. Should not fire. | |
157 | g(); | |
158 | v_some | |
159 | } else { | |
160 | return; | |
161 | }; | |
162 | ||
163 | let v = if let Some(v_some) = g() { | |
164 | v_some | |
165 | } else { | |
166 | if false { | |
167 | return; | |
168 | } | |
169 | // This doesn't diverge. Should not fire. | |
170 | () | |
171 | }; | |
172 | ||
173 | let v = if let Some(v_some) = g() { | |
174 | v_some | |
175 | } else { | |
176 | // There is one match arm that doesn't diverge. Should not fire. | |
177 | match (g(), g()) { | |
178 | (Some(_), None) => return, | |
179 | (None, Some(_)) => return, | |
180 | (Some(_), Some(_)) => (), | |
181 | _ => return, | |
182 | } | |
183 | }; | |
184 | ||
185 | let v = if let Some(v_some) = g() { | |
186 | v_some | |
187 | } else { | |
188 | // loop with a break statement inside does not diverge. | |
189 | loop { | |
190 | break; | |
191 | } | |
192 | }; | |
193 | ||
194 | enum Uninhabited {} | |
195 | fn un() -> Uninhabited { | |
196 | panic!() | |
197 | } | |
198 | let v = if let Some(v_some) = None { | |
199 | v_some | |
200 | } else { | |
201 | // Don't lint if the type is uninhabited but not ! | |
202 | un() | |
203 | }; | |
204 | ||
205 | fn question_mark() -> Option<()> { | |
206 | let v = if let Some(v) = g() { | |
207 | v | |
208 | } else { | |
209 | // Question mark does not diverge | |
210 | g()? | |
211 | }; | |
212 | Some(v) | |
213 | } | |
214 | ||
215 | // Macro boundary inside let | |
216 | macro_rules! some_or_return { | |
217 | ($e:expr) => { | |
218 | if let Some(v) = $e { v } else { return } | |
219 | }; | |
220 | } | |
221 | let v = some_or_return!(g()); | |
222 | ||
223 | // Also macro boundary inside let, but inside a macro | |
224 | macro_rules! create_binding_if_some_nf { | |
225 | ($n:ident, $e:expr) => { | |
226 | let $n = some_or_return!($e); | |
227 | }; | |
228 | } | |
229 | create_binding_if_some_nf!(v, g()); | |
230 | ||
231 | // Already a let-else | |
232 | let Some(a) = (if let Some(b) = Some(Some(())) { b } else { return }) else { panic!() }; | |
233 | ||
234 | // If a type annotation is present, don't lint as | |
235 | // expressing the type might be too hard | |
236 | let v: () = if let Some(v_some) = g() { v_some } else { panic!() }; | |
237 | ||
238 | // Issue 9940 | |
239 | // Suggestion should not expand macros | |
240 | macro_rules! macro_call { | |
241 | () => { | |
242 | return () | |
243 | }; | |
244 | } | |
245 | ||
246 | let ff = Some(1); | |
247 | let _ = match ff { | |
248 | Some(value) => value, | |
249 | _ => macro_call!(), | |
250 | }; | |
9ffffee4 FG |
251 | |
252 | // Issue 10296 | |
253 | // The let/else block in the else part is not divergent despite the presence of return | |
254 | let _x = if let Some(x) = Some(1) { | |
255 | x | |
256 | } else { | |
257 | let Some(_z) = Some(3) else { | |
258 | return | |
259 | }; | |
260 | 1 | |
261 | }; | |
487cf647 | 262 | } |