@@ -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,14 +59,17 @@ 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,
70
+ NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: IgnoreUntilEnd ( _) => {
71
+ first
72
+ } ,
67
73
NeverLoopResult :: Otherwise => second,
68
74
}
69
75
}
@@ -75,16 +81,29 @@ fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResul
75
81
( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
76
82
NeverLoopResult :: MayContinueMainLoop
77
83
} ,
84
+ ( NeverLoopResult :: IgnoreUntilEnd ( a) , _) | ( _, NeverLoopResult :: IgnoreUntilEnd ( a) ) => {
85
+ NeverLoopResult :: IgnoreUntilEnd ( a)
86
+ } ,
78
87
( NeverLoopResult :: AlwaysBreak , _) | ( _, NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
79
88
( NeverLoopResult :: Otherwise , NeverLoopResult :: Otherwise ) => NeverLoopResult :: Otherwise ,
80
89
}
81
90
}
82
91
83
92
// Combine two results where only one of the part may have been executed.
84
93
#[ must_use]
85
- fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult ) -> NeverLoopResult {
94
+ fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult , ignore_ids : & [ HirId ] ) -> NeverLoopResult {
86
95
match ( b1, b2) {
87
- ( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
96
+ ( NeverLoopResult :: IgnoreUntilEnd ( a) , NeverLoopResult :: IgnoreUntilEnd ( b) ) => {
97
+ if ignore_ids. iter ( ) . find ( |& e| e == & a || e == & b) . unwrap ( ) == & a {
98
+ NeverLoopResult :: IgnoreUntilEnd ( b)
99
+ } else {
100
+ NeverLoopResult :: IgnoreUntilEnd ( a)
101
+ }
102
+ } ,
103
+ ( NeverLoopResult :: IgnoreUntilEnd ( _) , NeverLoopResult :: AlwaysBreak )
104
+ | ( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: IgnoreUntilEnd ( _) | NeverLoopResult :: AlwaysBreak ) => {
105
+ NeverLoopResult :: AlwaysBreak
106
+ } ,
88
107
( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
89
108
NeverLoopResult :: MayContinueMainLoop
90
109
} ,
@@ -103,7 +122,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
103
122
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
104
123
// els is an else block in a let...else binding
105
124
els. map_or ( e, |els| {
106
- combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) )
125
+ combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) , ignore_ids )
107
126
} )
108
127
} )
109
128
. fold ( NeverLoopResult :: Otherwise , combine_seq)
@@ -159,7 +178,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
159
178
let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
160
179
never_loop_expr ( e, ignore_ids, main_loop_id)
161
180
} ) ;
162
- combine_seq ( e1, combine_branches ( e2, e3) )
181
+ combine_seq ( e1, combine_branches ( e2, e3, ignore_ids ) )
163
182
} ,
164
183
ExprKind :: Match ( e, arms, _) => {
165
184
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
@@ -176,7 +195,10 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
176
195
}
177
196
let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
178
197
ignore_ids. pop ( ) ;
179
- ret
198
+ match ret {
199
+ NeverLoopResult :: IgnoreUntilEnd ( a) if a == b. hir_id => NeverLoopResult :: Otherwise ,
200
+ _ => ret,
201
+ }
180
202
} ,
181
203
ExprKind :: Continue ( d) => {
182
204
let id = d
@@ -190,7 +212,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
190
212
} ,
191
213
// checks if break targets a block instead of a loop
192
214
ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
193
- . map_or ( NeverLoopResult :: Otherwise , |e| {
215
+ . map_or ( NeverLoopResult :: IgnoreUntilEnd ( t ) , |e| {
194
216
never_loop_expr ( e, ignore_ids, main_loop_id)
195
217
} ) ,
196
218
ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
@@ -242,8 +264,11 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
242
264
ignore_ids : & mut Vec < HirId > ,
243
265
main_loop_id : HirId ,
244
266
) -> NeverLoopResult {
267
+ let ignore_ids_saved = ignore_ids. clone ( ) ;
245
268
e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
246
- . fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
269
+ . fold ( NeverLoopResult :: AlwaysBreak , |a, b| {
270
+ combine_branches ( a, b, & ignore_ids_saved)
271
+ } )
247
272
}
248
273
249
274
fn for_to_if_let_sugg ( cx : & LateContext < ' _ > , iterator : & Expr < ' _ > , pat : & Pat < ' _ > ) -> String {
0 commit comments