@@ -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,22 +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,
70
+ NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: IgnoreUntilEnd ( _) => {
71
+ first
72
+ } ,
67
73
NeverLoopResult :: Otherwise => second,
68
74
}
69
75
}
70
76
71
77
// Combine two results where only one of the part may have been executed.
72
78
#[ must_use]
73
- fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult ) -> NeverLoopResult {
79
+ fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult , ignore_ids : & [ HirId ] ) -> NeverLoopResult {
74
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,
75
90
( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
76
91
( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
77
92
NeverLoopResult :: MayContinueMainLoop
@@ -91,7 +106,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
91
106
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
92
107
// els is an else block in a let...else binding
93
108
els. map_or ( e, |els| {
94
- 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 )
95
110
} )
96
111
} )
97
112
. fold ( NeverLoopResult :: Otherwise , combine_seq)
@@ -147,7 +162,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
147
162
let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
148
163
never_loop_expr ( e, ignore_ids, main_loop_id)
149
164
} ) ;
150
- combine_seq ( e1, combine_branches ( e2, e3) )
165
+ combine_seq ( e1, combine_branches ( e2, e3, ignore_ids ) )
151
166
} ,
152
167
ExprKind :: Match ( e, arms, _) => {
153
168
let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
@@ -166,7 +181,10 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
166
181
if l. is_some ( ) {
167
182
ignore_ids. pop ( ) ;
168
183
}
169
- ret
184
+ match ret {
185
+ NeverLoopResult :: IgnoreUntilEnd ( a) if a == b. hir_id => NeverLoopResult :: Otherwise ,
186
+ _ => ret,
187
+ }
170
188
} ,
171
189
ExprKind :: Continue ( d) => {
172
190
let id = d
@@ -180,7 +198,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
180
198
} ,
181
199
// checks if break targets a block instead of a loop
182
200
ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
183
- . map_or ( NeverLoopResult :: Otherwise , |e| {
201
+ . map_or ( NeverLoopResult :: IgnoreUntilEnd ( t ) , |e| {
184
202
never_loop_expr ( e, ignore_ids, main_loop_id)
185
203
} ) ,
186
204
ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
@@ -232,8 +250,9 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
232
250
ignore_ids : & mut Vec < HirId > ,
233
251
main_loop_id : HirId ,
234
252
) -> NeverLoopResult {
235
- e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
236
- . 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
+ } )
237
256
}
238
257
239
258
fn for_to_if_let_sugg ( cx : & LateContext < ' _ > , iterator : & Expr < ' _ > , pat : & Pat < ' _ > ) -> String {
0 commit comments