]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/tests/ui/manual_let_else.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / src / tools / clippy / tests / ui / manual_let_else.rs
CommitLineData
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
11fn g() -> Option<()> {
12 None
13}
14
15fn main() {}
16
17fn 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
140fn 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}