Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[let_chains, 3/6] And then there was only Loop #61988

Merged
merged 12 commits into from
Jul 6, 2019
42 changes: 0 additions & 42 deletions src/librustc/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,48 +165,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
}

hir::ExprKind::While(ref cond, ref body, _) => {
//
// [pred]
// |
// v 1
// [loopback] <--+ 5
// | |
// v 2 |
// +-----[cond] |
// | | |
// | v 4 |
// | [body] -----+
// v 3
// [expr]
//
// Note that `break` and `continue` statements
// may cause additional edges.

let loopback = self.add_dummy_node(&[pred]); // 1

// Create expr_exit without pred (cond_exit)
let expr_exit = self.add_ast_node(expr.hir_id.local_id, &[]); // 3

// The LoopScope needs to be on the loop_scopes stack while evaluating the
// condition and the body of the loop (both can break out of the loop)
self.loop_scopes.push(LoopScope {
loop_id: expr.hir_id.local_id,
continue_index: loopback,
break_index: expr_exit
});

let cond_exit = self.expr(&cond, loopback); // 2

// Add pred (cond_exit) to expr_exit
self.add_contained_edge(cond_exit, expr_exit);

let body_exit = self.block(&body, cond_exit); // 4
self.add_contained_edge(body_exit, loopback); // 5
self.loop_scopes.pop();
expr_exit
}

hir::ExprKind::Loop(ref body, _, _) => {
//
// [pred]
Expand Down
5 changes: 0 additions & 5 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1026,11 +1026,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
ExprKind::DropTemps(ref subexpression) => {
visitor.visit_expr(subexpression);
}
ExprKind::While(ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
ExprKind::Loop(ref block, ref opt_label, _) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
Expand Down
138 changes: 72 additions & 66 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use syntax::errors;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::print::pprust;
use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned};
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
use syntax::source_map::CompilerDesugaringKind::CondTemporary;
use syntax::std_inject;
use syntax::symbol::{kw, sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
Expand Down Expand Up @@ -4394,21 +4394,18 @@ impl<'a> LoweringContext<'a> {
let then_blk = self.lower_block(then, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
let (then_pats, scrutinee, desugar) = match cond.node {
// `<pat> => <then>`
// `<pat> => <then>`:
ExprKind::Let(ref pats, ref scrutinee) => {
let scrutinee = self.lower_expr(scrutinee);
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
(pats, scrutinee, desugar)
}
// `true => then`:
// `true => <then>`:
_ => {
// Lower condition:
let cond = self.lower_expr(cond);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `if cond { ... }`
// don't let temporaries live outside of `cond`.
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
let span_block = self.mark_span_with_reason(CondTemporary, cond.span, None);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `if cond { ... }` does not
// let temporaries live outside of `cond`.
Expand All @@ -4424,69 +4421,78 @@ impl<'a> LoweringContext<'a> {
hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
}
// FIXME(#53667): handle lowering of && and parens.
ExprKind::While(ref cond, ref body, opt_label) => {
// Desugar `ExprWhileLet`
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
if let ExprKind::Let(ref pats, ref sub_expr) = cond.node {
// to:
//
// [opt_ident]: loop {
// match <sub_expr> {
// <pat> => <body>,
// _ => break
// }
// }

// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
(
this.lower_block(body, false),
this.expr_break(e.span, ThinVec::new()),
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
)
});
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.

// `<pat> => <body>`
let pat_arm = {
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
self.arm(pats, body_expr)
};
// `_ => break`:
let else_arm = {
let else_pat = this.pat_wild(e.span);
let else_expr = this.expr_break(e.span, ThinVec::new());
this.arm(hir_vec![else_pat], else_expr)
};

// `_ => break`
let break_arm = {
let pat_under = self.pat_wild(e.span);
self.arm(hir_vec![pat_under], break_expr)
};
// Handle then + scrutinee:
let then_blk = this.lower_block(body, false);
let then_expr = this.expr_block(then_blk, ThinVec::new());
let (then_pats, scrutinee, desugar, source) = match cond.node {
ExprKind::Let(ref pats, ref scrutinee) => {
// to:
//
// [opt_ident]: loop {
// match <sub_expr> {
// <pat> => <body>,
// _ => break
// }
// }
let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect();
let desugar = hir::MatchSource::WhileLetDesugar;
(pats, scrutinee, desugar, hir::LoopSource::WhileLet)
}
_ => {
// We desugar: `'label: while $cond $body` into:
//
// ```
// 'label: loop {
// match DropTemps($cond) {
// true => $body,
// _ => break,
// }
// }
// ```

// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
let match_expr = self.expr(
sub_expr.span,
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
ThinVec::new(),
);
// Lower condition:
let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond));
let span_block = this.mark_span_with_reason(CondTemporary, cond.span, None);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `while cond { ... }` does not
// let temporaries live outside of `cond`.
let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new());

// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
let loop_expr = hir::ExprKind::Loop(
loop_block,
self.lower_label(opt_label),
hir::LoopSource::WhileLet,
);
// Add attributes to the outer returned expr node.
loop_expr
} else {
self.with_loop_scope(e.id, |this| {
hir::ExprKind::While(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false),
this.lower_label(opt_label),
)
})
}
}
let desugar = hir::MatchSource::WhileDesugar;
// `true => <then>`:
let pats = hir_vec![this.pat_bool(e.span, true)];
(pats, cond, desugar, hir::LoopSource::While)
}
};
let then_arm = this.arm(then_pats, P(then_expr));

// `match <scrutinee> { ... }`
let match_expr = this.expr_match(
scrutinee.span,
P(scrutinee),
hir_vec![then_arm, else_arm],
desugar,
);

// `[opt_ident]: loop { ... }`
hir::ExprKind::Loop(
P(this.block_expr(P(match_expr))),
this.lower_label(opt_label),
source
)
}),
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::Loop(
this.lower_block(body, false),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ impl<'hir> Map<'hir> {
match *node {
Node::Expr(ref expr) => {
match expr.node {
ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Ret(..) => true,
ExprKind::Loop(..) | ExprKind::Ret(..) => true,
_ => false,
}
}
Expand Down
21 changes: 15 additions & 6 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,6 @@ impl Expr {
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
ExprKind::While(..) => ExprPrecedence::While,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure,
Expand Down Expand Up @@ -1464,7 +1463,6 @@ impl Expr {
ExprKind::Break(..) |
ExprKind::Continue(..) |
ExprKind::Ret(..) |
ExprKind::While(..) |
ExprKind::Loop(..) |
ExprKind::Assign(..) |
ExprKind::InlineAsm(..) |
Expand Down Expand Up @@ -1532,10 +1530,6 @@ pub enum ExprKind {
/// This construct only exists to tweak the drop order in HIR lowering.
/// An example of that is the desugaring of `for` loops.
DropTemps(P<Expr>),
/// A while loop, with an optional label
///
/// I.e., `'label: while expr { <block> }`.
While(P<Expr>, P<Block>, Option<Label>),
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
///
/// I.e., `'label: loop { <block> }`.
Expand Down Expand Up @@ -1653,6 +1647,8 @@ pub enum MatchSource {
IfLetDesugar {
contains_else_clause: bool,
},
/// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
WhileDesugar,
/// A `while let _ = _ { .. }` (which was desugared to a
/// `loop { match _ { .. } }`).
WhileLetDesugar,
Expand All @@ -1669,12 +1665,25 @@ pub enum MatchSource {
pub enum LoopSource {
/// A `loop { .. }` loop.
Loop,
/// A `while _ { .. }` loop.
While,
/// A `while let _ = _ { .. }` loop.
WhileLet,
/// A `for _ in _ { .. }` loop.
ForLoop,
}

impl LoopSource {
pub fn name(self) -> &'static str {
match self {
LoopSource::Loop => "loop",
LoopSource::While => "while",
LoopSource::WhileLet => "while let",
LoopSource::ForLoop => "for",
}
}
}

#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
pub enum LoopIdError {
OutsideLoopScope,
Expand Down
11 changes: 0 additions & 11 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1299,16 +1299,6 @@ impl<'a> State<'a> {
// Print `}`:
self.bclose_maybe_open(expr.span, indent_unit, true);
}
hir::ExprKind::While(ref test, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
}
self.head("while");
self.print_expr_as_cond(&test);
self.s.space();
self.print_block(&blk);
}
hir::ExprKind::Loop(ref blk, opt_label, _) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
Expand Down Expand Up @@ -2289,7 +2279,6 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
match e.node {
hir::ExprKind::Match(..) |
hir::ExprKind::Block(..) |
hir::ExprKind::While(..) |
hir::ExprKind::Loop(..) => false,
_ => true,
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
});

impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
IfTemporary,
CondTemporary,
Async,
Await,
QuestionMark,
Expand Down
5 changes: 0 additions & 5 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.walk_block(&blk);
}

hir::ExprKind::While(ref cond_expr, ref blk, _) => {
self.consume_expr(&cond_expr);
self.walk_block(&blk);
}

hir::ExprKind::Unary(_, ref lhs) => {
self.consume_expr(&lhs);
}
Expand Down
Loading