@@ -39,6 +39,7 @@ pub(super) fn check(
39
39
} ) ;
40
40
} ,
41
41
NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: Otherwise => ( ) ,
42
+ NeverLoopResult :: IgnoreUntilEnd ( _) => unreachable ! ( ) ,
42
43
}
43
44
}
44
45
@@ -48,6 +49,8 @@ enum NeverLoopResult {
48
49
AlwaysBreak ,
49
50
// A continue may occur for the main loop.
50
51
MayContinueMainLoop ,
52
+ // Ignore everything until the end of the block with this id
53
+ IgnoreUntilEnd ( HirId ) ,
51
54
Otherwise ,
52
55
}
53
56
@@ -56,34 +59,34 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
56
59
match arg {
57
60
NeverLoopResult :: AlwaysBreak | NeverLoopResult :: Otherwise => NeverLoopResult :: Otherwise ,
58
61
NeverLoopResult :: MayContinueMainLoop => NeverLoopResult :: MayContinueMainLoop ,
62
+ NeverLoopResult :: IgnoreUntilEnd ( id) => NeverLoopResult :: IgnoreUntilEnd ( id) ,
59
63
}
60
64
}
61
65
62
66
// Combine two results for parts that are called in order.
63
67
#[ must_use]
64
68
fn combine_seq ( first : NeverLoopResult , second : NeverLoopResult ) -> NeverLoopResult {
65
69
match first {
66
- NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop => first,
67
- NeverLoopResult :: Otherwise => second,
68
- }
69
- }
70
-
71
- // Combine two results where both parts are called but not necessarily in order.
72
- #[ must_use]
73
- fn combine_both ( left : NeverLoopResult , right : NeverLoopResult ) -> NeverLoopResult {
74
- match ( left, right) {
75
- ( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
76
- NeverLoopResult :: MayContinueMainLoop
70
+ NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: IgnoreUntilEnd ( _) => {
71
+ first
77
72
} ,
78
- ( NeverLoopResult :: AlwaysBreak , _) | ( _, NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
79
- ( NeverLoopResult :: Otherwise , NeverLoopResult :: Otherwise ) => NeverLoopResult :: Otherwise ,
73
+ NeverLoopResult :: Otherwise => second,
80
74
}
81
75
}
82
76
83
77
// Combine two results where only one of the part may have been executed.
84
78
#[ must_use]
85
- fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult ) -> NeverLoopResult {
79
+ fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult , ignore_ids : & [ HirId ] ) -> NeverLoopResult {
86
80
match ( b1, b2) {
81
+ ( NeverLoopResult :: IgnoreUntilEnd ( a) , NeverLoopResult :: IgnoreUntilEnd ( b) ) => {
82
+ if ignore_ids. iter ( ) . find ( |& e| e == & a || e == & b) . unwrap ( ) == & a {
83
+ NeverLoopResult :: IgnoreUntilEnd ( b)
84
+ } else {
85
+ NeverLoopResult :: IgnoreUntilEnd ( a)
86
+ }
87
+ } ,
88
+ ( i @ NeverLoopResult :: IgnoreUntilEnd ( _) , NeverLoopResult :: AlwaysBreak )
89
+ | ( NeverLoopResult :: AlwaysBreak , i @ NeverLoopResult :: IgnoreUntilEnd ( _) ) => i,
87
90
( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
88
91
( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
89
92
NeverLoopResult :: MayContinueMainLoop
@@ -103,7 +106,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
103
106
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
104
107
// els is an else block in a let...else binding
105
108
els. map_or ( e, |els| {
106
- combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) )
109
+ combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) , ignore_ids )
107
110
} )
108
111
} )
109
112
. fold ( NeverLoopResult :: Otherwise , combine_seq)
@@ -139,7 +142,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
139
142
ExprKind :: Struct ( _, fields, base) => {
140
143
let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , ignore_ids, main_loop_id) ;
141
144
if let Some ( base) = base {
142
- combine_both ( fields, never_loop_expr ( base, ignore_ids, main_loop_id) )
145
+ combine_seq ( fields, never_loop_expr ( base, ignore_ids, main_loop_id) )
143
146
} else {
144
147
fields
145
148
}
@@ -159,7 +162,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
159
162
let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
160
163
never_loop_expr ( e, ignore_ids, main_loop_id)
161
164
} ) ;
162
- combine_seq ( e1, combine_branches ( e2, e3) )
165
+ combine_seq ( e1, combine_branches ( e2, e3, ignore_ids ) )
163
166
} ,
164
167
ExprKind :: Match ( e, arms, _) => {
165
168
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
@@ -175,8 +178,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
175
178
ignore_ids. push ( b. hir_id ) ;
176
179
}
177
180
let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
178
- ignore_ids. pop ( ) ;
179
- ret
181
+ if l. is_some ( ) {
182
+ ignore_ids. pop ( ) ;
183
+ }
184
+ match ret {
185
+ NeverLoopResult :: IgnoreUntilEnd ( a) if a == b. hir_id => NeverLoopResult :: Otherwise ,
186
+ _ => ret,
187
+ }
180
188
} ,
181
189
ExprKind :: Continue ( d) => {
182
190
let id = d
@@ -190,8 +198,8 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
190
198
} ,
191
199
// checks if break targets a block instead of a loop
192
200
ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
193
- . map_or ( NeverLoopResult :: Otherwise , |e| {
194
- combine_seq ( never_loop_expr ( e, ignore_ids, main_loop_id) , NeverLoopResult :: Otherwise )
201
+ . map_or ( NeverLoopResult :: IgnoreUntilEnd ( t ) , |e| {
202
+ never_loop_expr ( e, ignore_ids, main_loop_id)
195
203
} ) ,
196
204
ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
197
205
combine_seq (
@@ -218,7 +226,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
218
226
| InlineAsmOperand :: SymFn { .. }
219
227
| InlineAsmOperand :: SymStatic { .. } => NeverLoopResult :: Otherwise ,
220
228
} )
221
- . fold ( NeverLoopResult :: Otherwise , combine_both ) ,
229
+ . fold ( NeverLoopResult :: Otherwise , combine_seq ) ,
222
230
ExprKind :: Yield ( _, _)
223
231
| ExprKind :: Closure { .. }
224
232
| ExprKind :: Path ( _)
@@ -234,16 +242,17 @@ fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
234
242
main_loop_id : HirId ,
235
243
) -> NeverLoopResult {
236
244
es. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
237
- . fold ( NeverLoopResult :: Otherwise , combine_both )
245
+ . fold ( NeverLoopResult :: Otherwise , combine_seq )
238
246
}
239
247
240
248
fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
241
249
e : & mut T ,
242
250
ignore_ids : & mut Vec < HirId > ,
243
251
main_loop_id : HirId ,
244
252
) -> NeverLoopResult {
245
- e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
246
- . fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
253
+ e. fold ( NeverLoopResult :: AlwaysBreak , |a, b| {
254
+ combine_branches ( a, never_loop_expr ( b, ignore_ids, main_loop_id) , ignore_ids)
255
+ } )
247
256
}
248
257
249
258
fn for_to_if_let_sugg ( cx : & LateContext < ' _ > , iterator : & Expr < ' _ > , pat : & Pat < ' _ > ) -> String {
0 commit comments