// check for never_loop
match expr.node {
- ExprWhile(_, ref block, _) |
- ExprLoop(ref block, _, _) => {
+ ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => {
- let mut state = NeverLoopState {
- breaks: HashSet::new(),
- continues: HashSet::new(),
- };
- let may_complete = never_loop_block(block, &mut state);
- if !may_complete && !state.continues.contains(&expr.id) {
- span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops");
+ match never_loop_block(block, &expr.id) {
+ NeverLoopResult::AlwaysBreak =>
+ span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
+ NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
}
},
_ => (),
ExprField(ref e, _) |
ExprTupField(ref e, _) |
ExprAddrOf(_, ref e) |
- ExprRepeat(ref e, _) => never_loop_expr(e, state),
+ ExprStruct(_, _, Some(ref e)) |
+ ExprRepeat(ref e, _) => never_loop_expr(e, main_loop_id),
- ExprArray(ref es) |
- ExprMethodCall(_, _, ref es) |
- ExprTup(ref es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
+ ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => {
- never_loop_expr_seq(&mut es.iter(), state)
++ never_loop_expr_all(&mut es.iter(), main_loop_id)
+ },
- ExprCall(ref e, ref es) => never_loop_expr_seq(&mut once(&**e).chain(es.iter()), state),
+ ExprCall(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
ExprBinary(_, ref e1, ref e2) |
ExprAssign(ref e1, ref e2) |
ExprAssignOp(_, ref e1, ref e2) |
- ExprIndex(ref e1, ref e2) => never_loop_expr_seq(&mut [&**e1, &**e2].iter().cloned(), state),
+ ExprIndex(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
ExprIf(ref e, ref e2, ref e3) => {
- let e1 = never_loop_expr(e, state);
- let e2 = never_loop_expr(e2, state);
- match *e3 {
- Some(ref e3) => {
- let e3 = never_loop_expr(e3, state);
- e1 && (e2 || e3)
- },
- None => e1,
- }
+ let e1 = never_loop_expr(e, main_loop_id);
+ let e2 = never_loop_expr(e2, main_loop_id);
+ let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
+ combine_seq(e1, combine_branches(e2, e3))
},
ExprLoop(ref b, _, _) => {
- let block_may_complete = never_loop_block(b, state);
- let has_break = state.breaks.remove(&expr.id);
- state.continues.remove(&expr.id);
- block_may_complete || has_break
+ // Break can come from the inner loop so remove them.
+ absorb_break(&never_loop_block(b, main_loop_id))
},
ExprWhile(ref e, ref b, _) => {
- let e = never_loop_expr(e, state);
- let block_may_complete = never_loop_block(b, state);
- let has_break = state.breaks.remove(&expr.id);
- let has_continue = state.continues.remove(&expr.id);
- e && (block_may_complete || has_break || has_continue)
+ let e = never_loop_expr(e, main_loop_id);
+ let result = never_loop_block(b, main_loop_id);
+ // Break can come from the inner loop so remove them.
+ combine_seq(e, absorb_break(&result))
},
ExprMatch(ref e, ref arms, _) => {
- let e = never_loop_expr(e, state);
- let arms = never_loop_expr_branch(&mut arms.iter().map(|a| &*a.body), state);
- e && arms
+ let e = never_loop_expr(e, main_loop_id);
+ if arms.is_empty() {
+ e
+ } else {
+ let arms = never_loop_expr_branch(&mut arms.iter().map(|a| &*a.body), main_loop_id);
+ combine_seq(e, arms)
+ }
},
- ExprBlock(ref b) => never_loop_block(b, state),
+ ExprBlock(ref b) => never_loop_block(b, main_loop_id),
ExprAgain(d) => {
- let id = d.target_id.opt_id().expect("target id can only be missing in the presence of compilation errors");
+ let id = d.target_id
+ .opt_id()
+ .expect("target id can only be missing in the presence of compilation errors");
- state.continues.insert(id);
- false
+ if id == *main_loop_id {
+ NeverLoopResult::MayContinueMainLoop
+ } else {
+ NeverLoopResult::AlwaysBreak
+ }
},
- ExprBreak(d, _) => {
- let id = d.target_id
- .opt_id()
- .expect("target id can only be missing in the presence of compilation errors");
- state.breaks.insert(id);
- false
+ ExprBreak(_, _) => {
+ NeverLoopResult::AlwaysBreak
},
ExprRet(ref e) => {
if let Some(ref e) = *e {
}
}
-fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, state: &mut NeverLoopState) -> bool {
- es.map(|e| never_loop_expr(e, state))
- .fold(true, |a, b| a && b)
+fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: &NodeId) -> NeverLoopResult {
- es.map(|e| never_loop_expr(e, main_loop_id)).fold(NeverLoopResult::Otherwise, combine_seq)
++ es.map(|e| never_loop_expr(e, main_loop_id))
++ .fold(NeverLoopResult::Otherwise, combine_seq)
+}
+
+fn never_loop_expr_all<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: &NodeId) -> NeverLoopResult {
- es.map(|e| never_loop_expr(e, main_loop_id)).fold(NeverLoopResult::Otherwise, combine_both)
++ es.map(|e| never_loop_expr(e, main_loop_id))
++ .fold(NeverLoopResult::Otherwise, combine_both)
}
-fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr>>(e: &mut T, state: &mut NeverLoopState) -> bool {
- e.map(|e| never_loop_expr(e, state))
- .fold(false, |a, b| a || b)
+fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, main_loop_id: &NodeId) -> NeverLoopResult {
- e.map(|e| never_loop_expr(e, main_loop_id)).fold(NeverLoopResult::AlwaysBreak, combine_branches)
++ e.map(|e| never_loop_expr(e, main_loop_id))
++ .fold(NeverLoopResult::AlwaysBreak, combine_branches)
}
fn check_for_loop<'a, 'tcx>(