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

Reintroduce hir::ExprKind::If #79328

Merged
merged 3 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 31 additions & 25 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Let(ref pat, ref scrutinee) => {
self.lower_expr_let(e.span, pat, scrutinee)
}
ExprKind::If(ref cond, ref then, ref else_opt) => {
self.lower_expr_if(e.span, cond, then, else_opt.as_deref())
}
ExprKind::If(ref cond, ref then, ref else_opt) => match cond.kind {
ExprKind::Let(ref pat, ref scrutinee) => {
self.lower_expr_if_let(e.span, pat, scrutinee, then, else_opt.as_deref())
}
_ => self.lower_expr_if(cond, then, else_opt.as_deref()),
},
ExprKind::While(ref cond, ref body, opt_label) => self
.with_loop_scope(e.id, |this| {
this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
Expand Down Expand Up @@ -337,10 +340,30 @@ impl<'hir> LoweringContext<'_, 'hir> {

fn lower_expr_if(
&mut self,
span: Span,
cond: &Expr,
then: &Block,
else_opt: Option<&Expr>,
) -> hir::ExprKind<'hir> {
macro_rules! make_if {
($opt:expr) => {{
let then_expr = self.lower_block_expr(then);
hir::ExprKind::If(self.lower_expr(cond), self.arena.alloc(then_expr), $opt)
}};
}
if let Some(rslt) = else_opt {
make_if!(Some(self.lower_expr(rslt)))
} else {
make_if!(None)
}
}

fn lower_expr_if_let(
&mut self,
span: Span,
pat: &Pat,
scrutinee: &Expr,
then: &Block,
else_opt: Option<&Expr>,
) -> hir::ExprKind<'hir> {
// FIXME(#53667): handle lowering of && and parens.

Expand All @@ -353,30 +376,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
let else_arm = self.arm(else_pat, else_expr);

// Handle then + scrutinee:
let (then_pat, scrutinee, desugar) = match cond.kind {
// `<pat> => <then>`:
ExprKind::Let(ref pat, ref scrutinee) => {
let scrutinee = self.lower_expr(scrutinee);
let pat = self.lower_pat(pat);
(pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause })
}
// `true => <then>`:
_ => {
// Lower condition:
let cond = self.lower_expr(cond);
let span_block =
self.mark_span_with_reason(DesugaringKind::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`.
let cond = self.expr_drop_temps(span_block, cond, ThinVec::new());
let pat = self.pat_bool(span, true);
(pat, cond, hir::MatchSource::IfDesugar { contains_else_clause })
}
};
let scrutinee = self.lower_expr(scrutinee);
let then_pat = self.lower_pat(pat);

let then_expr = self.lower_block_expr(then);
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));

let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar)
}

Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,7 @@ impl Expr<'_> {
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure,
Expand Down Expand Up @@ -1459,6 +1460,7 @@ impl Expr<'_> {
| ExprKind::MethodCall(..)
| ExprKind::Struct(..)
| ExprKind::Tup(..)
| ExprKind::If(..)
| ExprKind::Match(..)
| ExprKind::Closure(..)
| ExprKind::Block(..)
Expand Down Expand Up @@ -1575,6 +1577,10 @@ pub enum ExprKind<'hir> {
/// This construct only exists to tweak the drop order in HIR lowering.
/// An example of that is the desugaring of `for` loops.
DropTemps(&'hir Expr<'hir>),
/// An `if` block, with an optional else block.
///
/// I.e., `if <expr> { <expr> } else { <expr> }`.
If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>),
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
///
/// I.e., `'label: loop { <block> }`.
Expand Down Expand Up @@ -1728,8 +1734,6 @@ 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 },
/// An `if let _ = _ => { .. }` match guard.
Expand All @@ -1752,7 +1756,7 @@ impl MatchSource {
use MatchSource::*;
match self {
Normal => "match",
IfDesugar { .. } | IfLetDesugar { .. } | IfLetGuardDesugar => "if",
IfLetDesugar { .. } | IfLetGuardDesugar => "if",
WhileDesugar | WhileLetDesugar => "while",
ForLoopDesugar => "for",
TryDesugar => "?",
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::DropTemps(ref subexpression) => {
visitor.visit_expr(subexpression);
}
ExprKind::If(ref cond, ref then, ref else_opt) => {
visitor.visit_expr(cond);
visitor.visit_expr(then);
walk_list!(visitor, visit_expr, else_opt);
}
ExprKind::Loop(ref block, ref opt_label, _) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
Expand Down
55 changes: 54 additions & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,50 @@ impl<'a> State<'a> {
self.ann.post(self, AnnNode::Block(blk))
}

fn print_else(&mut self, els: Option<&hir::Expr<'_>>) {
match els {
Some(_else) => {
match _else.kind {
// "another else-if"
hir::ExprKind::If(ref i, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
self.s.word(" else if ");
self.print_expr_as_cond(&i);
self.s.space();
self.print_expr(&then);
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
hir::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
self.s.word(" else ");
self.print_block(&b)
}
// BLEAH, constraints would be great here
_ => {
panic!("print_if saw if with weird alternative");
}
}
}
_ => {}
}
}

pub fn print_if(
&mut self,
test: &hir::Expr<'_>,
blk: &hir::Expr<'_>,
elseopt: Option<&hir::Expr<'_>>,
) {
self.head("if");
self.print_expr_as_cond(test);
self.s.space();
self.print_expr(blk);
self.print_else(elseopt)
}

pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
self.ann.nested(self, Nested::Body(constant.body))
}
Expand Down Expand Up @@ -1352,6 +1396,9 @@ impl<'a> State<'a> {
// Print `}`:
self.bclose_maybe_open(expr.span, true);
}
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
}
hir::ExprKind::Loop(ref blk, opt_label, _) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
Expand Down Expand Up @@ -2436,7 +2483,13 @@ impl<'a> State<'a> {
//
// Duplicated from `parse::classify`, but adapted for the HIR.
fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool {
!matches!(e.kind, hir::ExprKind::Match(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..))
!matches!(
e.kind,
hir::ExprKind::If(..)
| hir::ExprKind::Match(..)
| hir::ExprKind::Block(..)
| hir::ExprKind::Loop(..)
)
}

/// This statement requires a semicolon after it.
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,20 +658,22 @@ impl<'hir> Map<'hir> {
CRATE_HIR_ID
}

/// When on a match arm tail expression or on a match arm, give back the enclosing `match`
/// expression.
/// When on an if expression, a match arm tail expression or a match arm, give back
/// the enclosing `if` or `match` expression.
///
/// Used by error reporting when there's a type error in a match arm caused by the `match`
/// Used by error reporting when there's a type error in an if or match arm caused by the
/// expression needing to be unit.
pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
pub fn get_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
for (_, node) in self.parent_iter(hir_id) {
match node {
Node::Item(_)
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::ImplItem(_)
| Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
Node::Expr(expr @ Expr { kind: ExprKind::Match(..), .. }) => return Some(expr),
Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
return Some(expr);
}
_ => {}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Match { .. }
| ExprKind::If { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }
| ExprKind::Assign { .. }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::StaticRef { .. }
| ExprKind::Block { .. }
| ExprKind::Match { .. }
| ExprKind::If { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Borrow { .. }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl Category {

ExprKind::LogicalOp { .. }
| ExprKind::Match { .. }
| ExprKind::If { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Adt { .. }
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::Match { scrutinee, arms } => {
this.match_expr(destination, scope, expr_span, block, scrutinee, arms)
}
ExprKind::If { cond, then, else_opt } => {
let place = unpack!(block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut));
let operand = Operand::Move(Place::from(place));

let mut then_block = this.cfg.start_new_block();
let mut else_block = this.cfg.start_new_block();
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
this.cfg.terminate(block, source_info, term);

unpack!(then_block = this.into(destination, scope, then_block, then));
else_block = if let Some(else_opt) = else_opt {
unpack!(this.into(destination, None, else_block, else_opt))
} else {
// Body of the `if` expression without an `else` clause must return `()`, thus
// we implicitly generate a `else {}` if it is not specified.
let correct_si = this.source_info(expr_span.shrink_to_hi());
this.cfg.push_assign_unit(else_block, correct_si, destination, this.hir.tcx());
else_block
};

let join_block = this.cfg.start_new_block();
this.cfg.terminate(
then_block,
source_info,
TerminatorKind::Goto { target: join_block },
);
this.cfg.terminate(
else_block,
source_info,
TerminatorKind::Goto { target: join_block },
);

join_block.unit()
},
ExprKind::NeverToAny { source } => {
let source = this.hir.mirror(source);
let is_call = matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
},
Err(err) => bug!("invalid loop id for continue: {}", err),
},
hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
cond: cond.to_ref(),
then: then.to_ref(),
else_opt: else_opt.map(|el| el.to_ref()),
},
hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
scrutinee: discr.to_ref(),
arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir_build/src/thir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ crate enum ExprKind<'tcx> {
Box {
value: ExprRef<'tcx>,
},
If {
cond: ExprRef<'tcx>,
then: ExprRef<'tcx>,
else_opt: Option<ExprRef<'tcx>>,
},
Call {
ty: Ty<'tcx>,
fun: ExprRef<'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ fn report_arm_reachability<'p, 'tcx>(
match is_useful {
NotUseful => {
match source {
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
hir::MatchSource::WhileDesugar => bug!(),

hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
// Check which arm we're on.
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_passes/src/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ impl NonConstExpr {

// All other expressions are allowed.
Self::Loop(Loop | While | WhileLet)
| Self::Match(
WhileDesugar | WhileLetDesugar | Normal | IfDesugar { .. } | IfLetDesugar { .. },
) => &[],
| Self::Match(WhileDesugar | WhileLetDesugar | Normal | IfLetDesugar { .. }) => &[],
};

Some(gates)
Expand Down
26 changes: 25 additions & 1 deletion compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
}

// live nodes required for interesting control flow:
hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
intravisit::walk_expr(self, expr);
}
Expand Down Expand Up @@ -846,6 +846,29 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// at the label ident
hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ),

hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
//
// (cond)
// |
// v
// (expr)
// / \
// | |
// v v
// (then)(els)
// | |
// v v
// ( succ )
//
let else_ln =
self.propagate_through_opt_expr(else_opt.as_ref().map(|e| &**e), succ);
let then_ln = self.propagate_through_expr(&then, succ);
let ln = self.live_node(expr.hir_id, expr.span);
self.init_from_succ(ln, else_ln);
self.merge_from_succ(ln, then_ln);
self.propagate_through_expr(&cond, ln)
}

hir::ExprKind::Match(ref e, arms, _) => {
//
// (e)
Expand Down Expand Up @@ -1336,6 +1359,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
| hir::ExprKind::Tup(..)
| hir::ExprKind::Binary(..)
| hir::ExprKind::Cast(..)
| hir::ExprKind::If(..)
| hir::ExprKind::DropTemps(..)
| hir::ExprKind::Unary(..)
| hir::ExprKind::Ret(..)
Expand Down
Loading