@@ -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,35 +59,36 @@ 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) {
87
- ( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
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
+ ( NeverLoopResult :: IgnoreUntilEnd ( _) , NeverLoopResult :: AlwaysBreak )
89
+ | ( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: IgnoreUntilEnd ( _) | NeverLoopResult :: AlwaysBreak ) => {
90
+ NeverLoopResult :: AlwaysBreak
91
+ } ,
88
92
( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
89
93
NeverLoopResult :: MayContinueMainLoop
90
94
} ,
@@ -103,7 +107,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
103
107
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
104
108
// els is an else block in a let...else binding
105
109
els. map_or ( e, |els| {
106
- combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) )
110
+ combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) , ignore_ids )
107
111
} )
108
112
} )
109
113
. fold ( NeverLoopResult :: Otherwise , combine_seq)
@@ -139,7 +143,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
139
143
ExprKind :: Struct ( _, fields, base) => {
140
144
let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , ignore_ids, main_loop_id) ;
141
145
if let Some ( base) = base {
142
- combine_both ( fields, never_loop_expr ( base, ignore_ids, main_loop_id) )
146
+ combine_seq ( fields, never_loop_expr ( base, ignore_ids, main_loop_id) )
143
147
} else {
144
148
fields
145
149
}
@@ -159,7 +163,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
159
163
let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
160
164
never_loop_expr ( e, ignore_ids, main_loop_id)
161
165
} ) ;
162
- combine_seq ( e1, combine_branches ( e2, e3) )
166
+ combine_seq ( e1, combine_branches ( e2, e3, ignore_ids ) )
163
167
} ,
164
168
ExprKind :: Match ( e, arms, _) => {
165
169
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
@@ -176,7 +180,10 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
176
180
}
177
181
let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
178
182
ignore_ids. pop ( ) ;
179
- ret
183
+ match ret {
184
+ NeverLoopResult :: IgnoreUntilEnd ( a) if a == b. hir_id => NeverLoopResult :: Otherwise ,
185
+ _ => ret,
186
+ }
180
187
} ,
181
188
ExprKind :: Continue ( d) => {
182
189
let id = d
@@ -190,7 +197,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
190
197
} ,
191
198
// checks if break targets a block instead of a loop
192
199
ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
193
- . map_or ( NeverLoopResult :: Otherwise , |e| {
200
+ . map_or ( NeverLoopResult :: IgnoreUntilEnd ( t ) , |e| {
194
201
never_loop_expr ( e, ignore_ids, main_loop_id)
195
202
} ) ,
196
203
ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
@@ -218,7 +225,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
218
225
| InlineAsmOperand :: SymFn { .. }
219
226
| InlineAsmOperand :: SymStatic { .. } => NeverLoopResult :: Otherwise ,
220
227
} )
221
- . fold ( NeverLoopResult :: Otherwise , combine_both ) ,
228
+ . fold ( NeverLoopResult :: Otherwise , combine_seq ) ,
222
229
ExprKind :: Yield ( _, _)
223
230
| ExprKind :: Closure { .. }
224
231
| ExprKind :: Path ( _)
@@ -234,16 +241,19 @@ fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
234
241
main_loop_id : HirId ,
235
242
) -> NeverLoopResult {
236
243
es. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
237
- . fold ( NeverLoopResult :: Otherwise , combine_both )
244
+ . fold ( NeverLoopResult :: Otherwise , combine_seq )
238
245
}
239
246
240
247
fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
241
248
e : & mut T ,
242
249
ignore_ids : & mut Vec < HirId > ,
243
250
main_loop_id : HirId ,
244
251
) -> NeverLoopResult {
252
+ let ignore_ids_saved = ignore_ids. clone ( ) ;
245
253
e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
246
- . fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
254
+ . fold ( NeverLoopResult :: AlwaysBreak , |a, b| {
255
+ combine_branches ( a, b, & ignore_ids_saved)
256
+ } )
247
257
}
248
258
249
259
fn for_to_if_let_sugg ( cx : & LateContext < ' _ > , iterator : & Expr < ' _ > , pat : & Pat < ' _ > ) -> String {
0 commit comments