diff --git a/src/loops.rs b/src/loops.rs index 10f58716dc7..7d7c97f1bb1 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -173,26 +173,32 @@ impl LateLintPass for LoopsPass { use `panic!()` or add `std::thread::sleep(..);` to \ the loop body."); } - - // extract the first statement (if any) in a block - let inner_stmt = extract_expr_from_first_stmt(block); - // extract a single expression + + // extract the expression from the first statement (if any) in a block + let inner_stmt_expr = extract_expr_from_first_stmt(block); + // extract the first expression (if any) from the block let inner_expr = extract_first_expr(block); - let extracted = match inner_stmt { - Some(_) => inner_stmt, - None => inner_expr, + let (extracted, collect_expr) = match inner_stmt_expr { + Some(_) => (inner_stmt_expr, true), // check if an expression exists in the first statement + None => (inner_expr, false), // if not, let's go for the first expression in the block }; if let Some(inner) = extracted { - // collect remaining expressions below the match - let other_stuff = block.stmts + if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { + // collect the remaining statements below the match + let mut other_stuff = block.stmts .iter() .skip(1) .map(|stmt| { format!("{}", snippet(cx, stmt.span, "..")) }).collect::>(); + if collect_expr { // if we have a statement which has a match, + match block.expr { // then collect the expression (without semicolon) below it + Some(ref expr) => other_stuff.push(format!("{}", snippet(cx, expr.span, ".."))), + None => (), + } + } - if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // ensure "if let" compatible match structure match *source { MatchSource::Normal | MatchSource::IfLetDesugar{..} => if @@ -203,7 +209,7 @@ impl LateLintPass for LoopsPass { is_break_expr(&arms[1].body) { if in_external_macro(cx, expr.span) { return; } - let loop_body = match inner_stmt { + let loop_body = match inner_stmt_expr { // FIXME: should probably be an ellipsis // tabbing and newline is probably a bad idea, especially for large blocks Some(_) => Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))), @@ -321,20 +327,12 @@ fn is_iterable_array(ty: ty::Ty) -> bool { /// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { - match block.expr { - Some(_) => None, - None if !block.stmts.is_empty() => match block.stmts[0].node { - StmtDecl(ref decl, _) => match decl.node { - DeclLocal(ref local) => match local.init { - Some(ref expr) => Some(expr), - None => None, - }, - _ => None, - }, - _ => None, - }, - _ => None, - } + if block.stmts.is_empty() { return None; } + if let StmtDecl(ref decl, _) = block.stmts[0].node { + if let DeclLocal(ref local) = decl.node { + if let Some(ref expr) = local.init { Some(expr) } else { None } + } else { None } + } else { None } } /// If a block begins with an expression (with or without semicolon), return it. diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index 8e51bf84887..a056fe249b5 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -33,6 +33,14 @@ fn main() { let _x = x; let _str = "foo"; } + loop { //~ERROR + let x = match y { + Some(x) => x, + None => break, + }; + { let _a = "bar"; }; + { let _b = "foobar"; } + } loop { // no error, else branch does something other than break match y { Some(_x) => true, @@ -53,7 +61,7 @@ fn main() { // cause this function to trigger it fn no_panic(slice: &[T]) { let mut iter = slice.iter(); - loop { + loop { //~ERROR let _ = match iter.next() { Some(ele) => ele, None => break