@@ -39,6 +39,7 @@ pub(super) fn check(
3939 } ) ;
4040 } ,
4141 NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: Otherwise => ( ) ,
42+ NeverLoopResult :: IgnoreUntilEnd ( _) => unreachable ! ( ) ,
4243 }
4344}
4445
@@ -48,6 +49,8 @@ enum NeverLoopResult {
4849 AlwaysBreak ,
4950 // A continue may occur for the main loop.
5051 MayContinueMainLoop ,
52+ // Ignore everything until the end of the block with this id
53+ IgnoreUntilEnd ( HirId ) ,
5154 Otherwise ,
5255}
5356
@@ -56,23 +59,36 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
5659 match arg {
5760 NeverLoopResult :: AlwaysBreak | NeverLoopResult :: Otherwise => NeverLoopResult :: Otherwise ,
5861 NeverLoopResult :: MayContinueMainLoop => NeverLoopResult :: MayContinueMainLoop ,
62+ NeverLoopResult :: IgnoreUntilEnd ( id) => NeverLoopResult :: IgnoreUntilEnd ( id) ,
5963 }
6064}
6165
6266// Combine two results for parts that are called in order.
6367#[ must_use]
6468fn combine_seq ( first : NeverLoopResult , second : NeverLoopResult ) -> NeverLoopResult {
6569 match first {
66- NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop => first,
70+ NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: IgnoreUntilEnd ( _) => {
71+ first
72+ } ,
6773 NeverLoopResult :: Otherwise => second,
6874 }
6975}
7076
7177// Combine two results where only one of the part may have been executed.
7278#[ must_use]
73- fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult ) -> NeverLoopResult {
79+ fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult , ignore_ids : & [ HirId ] ) -> NeverLoopResult {
7480 match ( b1, b2) {
75- ( 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+ } ,
7692 ( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
7793 NeverLoopResult :: MayContinueMainLoop
7894 } ,
@@ -91,7 +107,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
91107 let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
92108 // els is an else block in a let...else binding
93109 els. map_or ( e, |els| {
94- 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 )
95111 } )
96112 } )
97113 . fold ( NeverLoopResult :: Otherwise , combine_seq)
@@ -147,7 +163,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
147163 let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
148164 never_loop_expr ( e, ignore_ids, main_loop_id)
149165 } ) ;
150- combine_seq ( e1, combine_branches ( e2, e3) )
166+ combine_seq ( e1, combine_branches ( e2, e3, ignore_ids ) )
151167 } ,
152168 ExprKind :: Match ( e, arms, _) => {
153169 let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
@@ -164,7 +180,10 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
164180 }
165181 let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
166182 ignore_ids. pop ( ) ;
167- ret
183+ match ret {
184+ NeverLoopResult :: IgnoreUntilEnd ( a) if a == b. hir_id => NeverLoopResult :: Otherwise ,
185+ _ => ret,
186+ }
168187 } ,
169188 ExprKind :: Continue ( d) => {
170189 let id = d
@@ -178,7 +197,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
178197 } ,
179198 // checks if break targets a block instead of a loop
180199 ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
181- . map_or ( NeverLoopResult :: Otherwise , |e| {
200+ . map_or ( NeverLoopResult :: IgnoreUntilEnd ( t ) , |e| {
182201 never_loop_expr ( e, ignore_ids, main_loop_id)
183202 } ) ,
184203 ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
@@ -230,8 +249,11 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
230249 ignore_ids : & mut Vec < HirId > ,
231250 main_loop_id : HirId ,
232251) -> NeverLoopResult {
252+ let ignore_ids_saved = ignore_ids. clone ( ) ;
233253 e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
234- . fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
254+ . fold ( NeverLoopResult :: AlwaysBreak , |a, b| {
255+ combine_branches ( a, b, & ignore_ids_saved)
256+ } )
235257}
236258
237259fn for_to_if_let_sugg ( cx : & LateContext < ' _ > , iterator : & Expr < ' _ > , pat : & Pat < ' _ > ) -> String {
0 commit comments