Skip to content

Commit

Permalink
Auto merge of #59288 - Centril:hir-if-to-match, r=<try>
Browse files Browse the repository at this point in the history
[WIP] [let_chains, 1/6] Remove hir::ExprKind::If

Per #53667 (comment).

r? @oli-obk
  • Loading branch information
bors committed Apr 17, 2019
2 parents efe2f32 + 56156af commit 6a4b867
Show file tree
Hide file tree
Showing 40 changed files with 650 additions and 640 deletions.
42 changes: 1 addition & 41 deletions src/librustc/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,47 +166,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
}

hir::ExprKind::If(ref cond, ref then, None) => {
//
// [pred]
// |
// v 1
// [cond]
// |
// / \
// / \
// v 2 *
// [then] |
// | |
// v 3 v 4
// [..expr..]
//
let cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.expr(&then, cond_exit); // 2
self.add_ast_node(expr.hir_id.local_id, &[cond_exit, then_exit]) // 3,4
}

hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
//
// [pred]
// |
// v 1
// [cond]
// |
// / \
// / \
// v 2 v 3
// [then][otherwise]
// | |
// v 4 v 5
// [..expr..]
//
let cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.expr(&then, cond_exit); // 2
let else_exit = self.expr(&otherwise, cond_exit); // 3
self.add_ast_node(expr.hir_id.local_id, &[then_exit, else_exit]) // 4, 5
}

hir::ExprKind::While(ref cond, ref body, _) => {
//
// [pred]
Expand Down Expand Up @@ -369,6 +328,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
hir::ExprKind::AddrOf(_, ref e) |
hir::ExprKind::Cast(ref e, _) |
hir::ExprKind::Type(ref e, _) |
hir::ExprKind::Use(ref e) |
hir::ExprKind::Unary(_, ref e) |
hir::ExprKind::Field(ref e, _) |
hir::ExprKind::Yield(ref e) |
Expand Down
6 changes: 2 additions & 4 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,10 +1011,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_expr(subexpression);
visitor.visit_ty(typ)
}
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
visitor.visit_expr(head_expression);
visitor.visit_expr(if_block);
walk_list!(visitor, visit_expr, optional_else);
ExprKind::Use(ref subexpression) => {
visitor.visit_expr(subexpression);
}
ExprKind::While(ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
Expand Down
132 changes: 94 additions & 38 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
use syntax::std_inject;
use syntax::symbol::{keywords, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
Expand Down Expand Up @@ -4035,32 +4036,44 @@ impl<'a> LoweringContext<'a> {
}
// More complicated than you might expect because the else branch
// might be `if let`.
ExprKind::If(ref cond, ref blk, ref else_opt) => {
let else_opt = else_opt.as_ref().map(|els| {
match els.node {
ExprKind::If(ref cond, ref then, ref else_opt) => {
// `true => then`:
let then_pat = self.pat_bool(e.span, true);
let then_blk = self.lower_block(then, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
let then_arm = self.arm(hir_vec![then_pat], P(then_expr));

// `_ => else_block` where `else_block` is `()` if there's `None`:
let else_pat = self.pat_wild(e.span);
let else_expr = match else_opt {
None => self.expr_block_empty(e.span),
Some(els) => match els.node {
ExprKind::IfLet(..) => {
// Wrap the `if let` expr in a block.
let span = els.span;
let els = P(self.lower_expr(els));
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
let blk = P(hir::Block {
stmts: hir_vec![],
expr: Some(els),
hir_id,
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
});
P(self.expr_block(blk, ThinVec::new()))
let els = self.lower_expr(els);
let blk = self.block_all(els.span, hir_vec![], Some(P(els)));
self.expr_block(P(blk), ThinVec::new())
}
_ => P(self.lower_expr(els)),
_ => self.lower_expr(els),
}
});
};
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));

let then_blk = self.lower_block(blk, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
// Lower condition:
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
let cond = self.lower_expr(cond);
//let bool_ty = Some(P(self.ty_bool(e.span)));
// FIXME(centril, oli-obk): This is silly but we must wrap the condition expression
// in a block `{ let _t = $cond; _t }` to preserve drop semantics.
let cond = self.expr_temp(span_block, P(cond));//, bool_ty);

hir::ExprKind::If(P(self.lower_expr(cond)), P(then_expr), else_opt)
hir::ExprKind::Match(
P(cond),
vec![then_arm, else_arm].into(),
hir::MatchSource::IfDesugar {
contains_else_clause: else_opt.is_some()
},
)
}
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::While(
Expand Down Expand Up @@ -4654,6 +4667,8 @@ impl<'a> LoweringContext<'a> {

// `{ let _result = ...; _result }`
// Underscore prevents an `unused_variables` lint if the head diverges.
// https://github.com/rust-lang/rust/commit/b445bf2bd1139236fd815bf93610ddaf17726111
// FIXME(centril): Consider optimizing with `ExprKind::Use`.
let result_ident = self.str_to_ident("_result");
let (let_stmt, let_stmt_binding) =
self.stmt_let(e.span, false, result_ident, match_expr);
Expand Down Expand Up @@ -5023,6 +5038,26 @@ impl<'a> LoweringContext<'a> {
)
}

/// Wrap the given `expr` in `{ let _tmp[: ty]? = expr; _tmp }`.
/// This can be important for drop order of e.g. `if expr { .. }`.
fn expr_temp(
&mut self,
span: Span,
//source: hir::LocalSource,
expr: P<hir::Expr>,
//ty: Option<P<hir::Ty>>
) -> hir::Expr {
/*
let tident = self.str_to_ident("_tmp");
let (tpat, tpat_nid) = self.pat_ident(span, tident);
let tstmt = self.stmt_let_pat_ty(span, ty, Some(expr), tpat, source);
let access = self.expr_ident(span, tident, tpat_nid);
let block = self.block_all(span, hir_vec![tstmt], Some(P(access)));
self.expr_block(P(block), ThinVec::new())
*/
self.expr(span, hir::ExprKind::Use(expr), ThinVec::new())
}

fn expr_match(
&mut self,
span: Span,
Expand Down Expand Up @@ -5051,31 +5086,28 @@ impl<'a> LoweringContext<'a> {
}
}

fn stmt_let_pat_ty(
&mut self,
span: Span,
ty: Option<P<hir::Ty>>,
init: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
source: hir::LocalSource,
) -> hir::Stmt {
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
let local = hir::Local { pat, ty, init, hir_id, span, source, attrs: ThinVec::new() };
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
hir::Stmt { span, hir_id, node: hir::StmtKind::Local(P(local)) }
}

fn stmt_let_pat(
&mut self,
sp: Span,
ex: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
source: hir::LocalSource,
) -> hir::Stmt {
let LoweredNodeId { node_id: _, hir_id } = self.next_id();

let local = hir::Local {
pat,
ty: None,
init: ex,
hir_id,
span: sp,
attrs: ThinVec::new(),
source,
};

let LoweredNodeId { node_id: _, hir_id } = self.next_id();
hir::Stmt {
hir_id,
node: hir::StmtKind::Local(P(local)),
span: sp
}
self.stmt_let_pat_ty(sp, None, ex, pat, source)
}

fn stmt_let(
Expand All @@ -5097,6 +5129,11 @@ impl<'a> LoweringContext<'a> {
)
}

fn expr_block_empty(&mut self, span: Span) -> hir::Expr {
let blk = self.block_all(span, hir_vec![], None);
self.expr_block(P(blk), ThinVec::new())
}

fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
}
Expand All @@ -5119,6 +5156,13 @@ impl<'a> LoweringContext<'a> {
}
}

/// Constructs a `true` or `false` literal pattern.
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
let lit = Spanned { span, node: LitKind::Bool(val) };
let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new());
self.pat(span, hir::PatKind::Lit(P(expr)))
}

fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
}
Expand Down Expand Up @@ -5209,6 +5253,18 @@ impl<'a> LoweringContext<'a> {
path
}

/*
/// Constructs and returns the type `bool`.
fn ty_bool(&mut self, span: Span) -> hir::Ty {
let id = self.next_id();
self.ty_path(id, span, hir::QPath::Resolved(None, P(hir::Path {
span,
segments: hir_vec![],
def: Def::PrimTy(hir::PrimTy::Bool)
})))
}
*/

fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> hir::Ty {
let mut id = id;
let node = match qpath {
Expand Down
16 changes: 10 additions & 6 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,7 @@ impl Expr {
ExprKind::Unary(..) => ExprPrecedence::Unary,
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::Use(ref expr, ..) => expr.precedence(),
ExprKind::While(..) => ExprPrecedence::While,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
Expand Down Expand Up @@ -1416,7 +1416,6 @@ impl Expr {
ExprKind::MethodCall(..) |
ExprKind::Struct(..) |
ExprKind::Tup(..) |
ExprKind::If(..) |
ExprKind::Match(..) |
ExprKind::Closure(..) |
ExprKind::Block(..) |
Expand All @@ -1437,6 +1436,7 @@ impl Expr {
ExprKind::Binary(..) |
ExprKind::Yield(..) |
ExprKind::Cast(..) |
ExprKind::Use(..) |
ExprKind::Err => {
false
}
Expand Down Expand Up @@ -1486,10 +1486,10 @@ pub enum ExprKind {
Cast(P<Expr>, P<Ty>),
/// A type reference (e.g., `Foo`).
Type(P<Expr>, P<Ty>),
/// An `if` block, with an optional else block.
///
/// I.e., `if <expr> { <expr> } else { <expr> }`.
If(P<Expr>, P<Expr>, Option<P<Expr>>),
/// Equivalent to `{ let _t = expr; _t }`.
/// Maps directly to `hair::ExprKind::Use`.
/// Only exists to tweak the drop order in HIR.
Use(P<Expr>),
/// A while loop, with an optional label
///
/// I.e., `'label: while expr { <block> }`.
Expand Down Expand Up @@ -1590,6 +1590,10 @@ pub enum LocalSource {
pub enum MatchSource {
/// A `match _ { .. }`.
Normal,
/// An `if _ { .. }` (optionally with `else { .. }`).
IfDesugar {
contains_else_clause: bool,
},
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
IfLetDesugar {
contains_else_clause: bool,
Expand Down
Loading

0 comments on commit 6a4b867

Please sign in to comment.