Skip to content

Commit

Permalink
Remove ExprKind::While from HIR.
Browse files Browse the repository at this point in the history
  • Loading branch information
Centril committed Jul 6, 2019
1 parent 481068a commit f8b32df
Show file tree
Hide file tree
Showing 21 changed files with 114 additions and 272 deletions.
42 changes: 0 additions & 42 deletions src/librustc/cfg/construct.rs
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
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
50 changes: 43 additions & 7 deletions src/librustc/hir/lowering.rs
Expand Up @@ -4461,11 +4461,11 @@ impl<'a> LoweringContext<'a> {
};

// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
let match_expr = self.expr(
let match_expr = self.expr_match(
sub_expr.span,
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
ThinVec::new(),
sub_expr,
hir_vec![pat_arm, break_arm],
hir::MatchSource::WhileLetDesugar,
);

// `[opt_ident]: loop { ... }`
Expand All @@ -4479,10 +4479,46 @@ impl<'a> LoweringContext<'a> {
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),
// We desugar: `'label: while $cond $body` into:
//
// ```
// 'label: loop {
// match DropTemps($cond) {
// true => $block,
// _ => break,
// }
// }
// ```

// `true => then`:
let then_pat = this.pat_bool(e.span, true);
let then_blk = this.lower_block(body, false);
let then_expr = this.expr_block(then_blk, ThinVec::new());
let then_arm = this.arm(hir_vec![then_pat], P(then_expr));

// `_ => break`:
let else_pat = this.pat_wild(e.span);
let else_expr = this.expr_break(e.span, ThinVec::new());
let else_arm = this.arm(hir_vec![else_pat], else_expr);

// Lower condition:
let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond));
// 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`.
let cond = this.expr_drop_temps(cond.span, P(cond), ThinVec::new());

let match_expr = this.expr_match(
cond.span,
P(cond),
vec![then_arm, else_arm].into(),
hir::MatchSource::WhileDesugar,
);

hir::ExprKind::Loop(
P(this.block_expr(P(match_expr))),
this.lower_label(opt_label),
hir::LoopSource::While,
)
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/hir/map/mod.rs
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
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
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
5 changes: 0 additions & 5 deletions src/librustc/middle/expr_use_visitor.rs
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
63 changes: 13 additions & 50 deletions src/librustc/middle/liveness.rs
Expand Up @@ -93,7 +93,6 @@
//! It is the responsibility of typeck to ensure that there are no
//! `return` expressions in a function declared as diverging.

use self::LoopKind::*;
use self::LiveNodeKind::*;
use self::VarKind::*;

Expand All @@ -120,14 +119,6 @@ use crate::hir::{Expr, HirId};
use crate::hir::def_id::DefId;
use crate::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};

/// For use with `propagate_through_loop`.
enum LoopKind<'a> {
/// An endless `loop` loop.
LoopLoop,
/// A `while` loop, with the given expression as condition.
WhileLoop(&'a Expr),
}

#[derive(Copy, Clone, PartialEq)]
struct Variable(u32);

Expand Down Expand Up @@ -517,7 +508,6 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr) {

// live nodes required for interesting control flow:
hir::ExprKind::Match(..) |
hir::ExprKind::While(..) |
hir::ExprKind::Loop(..) => {
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
intravisit::walk_expr(ir, expr);
Expand Down Expand Up @@ -1055,14 +1045,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
})
}

hir::ExprKind::While(ref cond, ref blk, _) => {
self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ)
}

// Note that labels have been resolved, so we don't need to look
// at the label ident
hir::ExprKind::Loop(ref blk, _, _) => {
self.propagate_through_loop(expr, LoopLoop, &blk, succ)
self.propagate_through_loop(expr, &blk, succ)
}

hir::ExprKind::Match(ref e, ref arms, _) => {
Expand Down Expand Up @@ -1353,13 +1339,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
}

fn propagate_through_loop(&mut self,
expr: &Expr,
kind: LoopKind<'_>,
body: &hir::Block,
succ: LiveNode)
-> LiveNode {
fn propagate_through_loop(
&mut self,
expr: &Expr,
body: &hir::Block,
succ: LiveNode
) -> LiveNode {
/*
FIXME: clean up this description.
We model control flow like this:
Expand All @@ -1377,50 +1364,26 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
*/


// first iteration:
let mut first_merge = true;
let ln = self.live_node(expr.hir_id, expr.span);
self.init_empty(ln, succ);
match kind {
LoopLoop => {}
_ => {
// If this is not a `loop` loop, then it's possible we bypass
// the body altogether. Otherwise, the only way is via a `break`
// in the loop body.
self.merge_from_succ(ln, succ, first_merge);
first_merge = false;
}
}
debug!("propagate_through_loop: using id for loop body {} {}",
expr.hir_id, self.ir.tcx.hir().hir_to_pretty_string(body.hir_id));

self.break_ln.insert(expr.hir_id, succ);

let cond_ln = match kind {
LoopLoop => ln,
WhileLoop(ref cond) => self.propagate_through_expr(&cond, ln),
};

self.cont_ln.insert(expr.hir_id, cond_ln);
self.cont_ln.insert(expr.hir_id, ln);

let body_ln = self.propagate_through_block(body, cond_ln);
let body_ln = self.propagate_through_block(body, ln);

// repeat until fixed point is reached:
while self.merge_from_succ(ln, body_ln, first_merge) {
first_merge = false;

let new_cond_ln = match kind {
LoopLoop => ln,
WhileLoop(ref cond) => {
self.propagate_through_expr(&cond, ln)
}
};
assert_eq!(cond_ln, new_cond_ln);
assert_eq!(body_ln, self.propagate_through_block(body, cond_ln));
assert_eq!(body_ln, self.propagate_through_block(body, ln));
}

cond_ln
ln
}
}

Expand Down Expand Up @@ -1520,7 +1483,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {

// no correctness conditions related to liveness
hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) |
hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) |
hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) | hir::ExprKind::Unary(..) |
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -696,7 +696,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) |
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) |
hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
hir::ExprKind::Binary(..) |
hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) |
hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
Expand Down
5 changes: 0 additions & 5 deletions src/librustc/middle/region.rs
Expand Up @@ -915,11 +915,6 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
terminating(body.hir_id.local_id);
}

hir::ExprKind::While(ref expr, ref body, _) => {
terminating(expr.hir_id.local_id);
terminating(body.hir_id.local_id);
}

hir::ExprKind::DropTemps(ref expr) => {
// `DropTemps(expr)` does not denote a conditional scope.
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
Expand Down

0 comments on commit f8b32df

Please sign in to comment.