Skip to content

Commit 6a4b867

Browse files
committed
Auto merge of #59288 - Centril:hir-if-to-match, r=<try>
[WIP] [let_chains, 1/6] Remove hir::ExprKind::If Per #53667 (comment). r? @oli-obk
2 parents efe2f32 + 56156af commit 6a4b867

40 files changed

+650
-640
lines changed

src/librustc/cfg/construct.rs

+1-41
Original file line numberDiff line numberDiff line change
@@ -166,47 +166,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
166166
self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
167167
}
168168

169-
hir::ExprKind::If(ref cond, ref then, None) => {
170-
//
171-
// [pred]
172-
// |
173-
// v 1
174-
// [cond]
175-
// |
176-
// / \
177-
// / \
178-
// v 2 *
179-
// [then] |
180-
// | |
181-
// v 3 v 4
182-
// [..expr..]
183-
//
184-
let cond_exit = self.expr(&cond, pred); // 1
185-
let then_exit = self.expr(&then, cond_exit); // 2
186-
self.add_ast_node(expr.hir_id.local_id, &[cond_exit, then_exit]) // 3,4
187-
}
188-
189-
hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
190-
//
191-
// [pred]
192-
// |
193-
// v 1
194-
// [cond]
195-
// |
196-
// / \
197-
// / \
198-
// v 2 v 3
199-
// [then][otherwise]
200-
// | |
201-
// v 4 v 5
202-
// [..expr..]
203-
//
204-
let cond_exit = self.expr(&cond, pred); // 1
205-
let then_exit = self.expr(&then, cond_exit); // 2
206-
let else_exit = self.expr(&otherwise, cond_exit); // 3
207-
self.add_ast_node(expr.hir_id.local_id, &[then_exit, else_exit]) // 4, 5
208-
}
209-
210169
hir::ExprKind::While(ref cond, ref body, _) => {
211170
//
212171
// [pred]
@@ -369,6 +328,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
369328
hir::ExprKind::AddrOf(_, ref e) |
370329
hir::ExprKind::Cast(ref e, _) |
371330
hir::ExprKind::Type(ref e, _) |
331+
hir::ExprKind::Use(ref e) |
372332
hir::ExprKind::Unary(_, ref e) |
373333
hir::ExprKind::Field(ref e, _) |
374334
hir::ExprKind::Yield(ref e) |

src/librustc/hir/intravisit.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1011,10 +1011,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
10111011
visitor.visit_expr(subexpression);
10121012
visitor.visit_ty(typ)
10131013
}
1014-
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
1015-
visitor.visit_expr(head_expression);
1016-
visitor.visit_expr(if_block);
1017-
walk_list!(visitor, visit_expr, optional_else);
1014+
ExprKind::Use(ref subexpression) => {
1015+
visitor.visit_expr(subexpression);
10181016
}
10191017
ExprKind::While(ref subexpression, ref block, ref opt_label) => {
10201018
walk_list!(visitor, visit_label, opt_label);

src/librustc/hir/lowering.rs

+94-38
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
6161
use syntax::print::pprust;
6262
use syntax::ptr::P;
6363
use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
64+
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
6465
use syntax::std_inject;
6566
use syntax::symbol::{keywords, Symbol};
6667
use syntax::tokenstream::{TokenStream, TokenTree};
@@ -4035,32 +4036,44 @@ impl<'a> LoweringContext<'a> {
40354036
}
40364037
// More complicated than you might expect because the else branch
40374038
// might be `if let`.
4038-
ExprKind::If(ref cond, ref blk, ref else_opt) => {
4039-
let else_opt = else_opt.as_ref().map(|els| {
4040-
match els.node {
4039+
ExprKind::If(ref cond, ref then, ref else_opt) => {
4040+
// `true => then`:
4041+
let then_pat = self.pat_bool(e.span, true);
4042+
let then_blk = self.lower_block(then, false);
4043+
let then_expr = self.expr_block(then_blk, ThinVec::new());
4044+
let then_arm = self.arm(hir_vec![then_pat], P(then_expr));
4045+
4046+
// `_ => else_block` where `else_block` is `()` if there's `None`:
4047+
let else_pat = self.pat_wild(e.span);
4048+
let else_expr = match else_opt {
4049+
None => self.expr_block_empty(e.span),
4050+
Some(els) => match els.node {
40414051
ExprKind::IfLet(..) => {
40424052
// Wrap the `if let` expr in a block.
4043-
let span = els.span;
4044-
let els = P(self.lower_expr(els));
4045-
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
4046-
let blk = P(hir::Block {
4047-
stmts: hir_vec![],
4048-
expr: Some(els),
4049-
hir_id,
4050-
rules: hir::DefaultBlock,
4051-
span,
4052-
targeted_by_break: false,
4053-
});
4054-
P(self.expr_block(blk, ThinVec::new()))
4053+
let els = self.lower_expr(els);
4054+
let blk = self.block_all(els.span, hir_vec![], Some(P(els)));
4055+
self.expr_block(P(blk), ThinVec::new())
40554056
}
4056-
_ => P(self.lower_expr(els)),
4057+
_ => self.lower_expr(els),
40574058
}
4058-
});
4059+
};
4060+
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
40594061

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

4063-
hir::ExprKind::If(P(self.lower_expr(cond)), P(then_expr), else_opt)
4070+
hir::ExprKind::Match(
4071+
P(cond),
4072+
vec![then_arm, else_arm].into(),
4073+
hir::MatchSource::IfDesugar {
4074+
contains_else_clause: else_opt.is_some()
4075+
},
4076+
)
40644077
}
40654078
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
40664079
hir::ExprKind::While(
@@ -4654,6 +4667,8 @@ impl<'a> LoweringContext<'a> {
46544667

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

5041+
/// Wrap the given `expr` in `{ let _tmp[: ty]? = expr; _tmp }`.
5042+
/// This can be important for drop order of e.g. `if expr { .. }`.
5043+
fn expr_temp(
5044+
&mut self,
5045+
span: Span,
5046+
//source: hir::LocalSource,
5047+
expr: P<hir::Expr>,
5048+
//ty: Option<P<hir::Ty>>
5049+
) -> hir::Expr {
5050+
/*
5051+
let tident = self.str_to_ident("_tmp");
5052+
let (tpat, tpat_nid) = self.pat_ident(span, tident);
5053+
let tstmt = self.stmt_let_pat_ty(span, ty, Some(expr), tpat, source);
5054+
let access = self.expr_ident(span, tident, tpat_nid);
5055+
let block = self.block_all(span, hir_vec![tstmt], Some(P(access)));
5056+
self.expr_block(P(block), ThinVec::new())
5057+
*/
5058+
self.expr(span, hir::ExprKind::Use(expr), ThinVec::new())
5059+
}
5060+
50265061
fn expr_match(
50275062
&mut self,
50285063
span: Span,
@@ -5051,31 +5086,28 @@ impl<'a> LoweringContext<'a> {
50515086
}
50525087
}
50535088

5089+
fn stmt_let_pat_ty(
5090+
&mut self,
5091+
span: Span,
5092+
ty: Option<P<hir::Ty>>,
5093+
init: Option<P<hir::Expr>>,
5094+
pat: P<hir::Pat>,
5095+
source: hir::LocalSource,
5096+
) -> hir::Stmt {
5097+
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
5098+
let local = hir::Local { pat, ty, init, hir_id, span, source, attrs: ThinVec::new() };
5099+
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
5100+
hir::Stmt { span, hir_id, node: hir::StmtKind::Local(P(local)) }
5101+
}
5102+
50545103
fn stmt_let_pat(
50555104
&mut self,
50565105
sp: Span,
50575106
ex: Option<P<hir::Expr>>,
50585107
pat: P<hir::Pat>,
50595108
source: hir::LocalSource,
50605109
) -> hir::Stmt {
5061-
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
5062-
5063-
let local = hir::Local {
5064-
pat,
5065-
ty: None,
5066-
init: ex,
5067-
hir_id,
5068-
span: sp,
5069-
attrs: ThinVec::new(),
5070-
source,
5071-
};
5072-
5073-
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
5074-
hir::Stmt {
5075-
hir_id,
5076-
node: hir::StmtKind::Local(P(local)),
5077-
span: sp
5078-
}
5110+
self.stmt_let_pat_ty(sp, None, ex, pat, source)
50795111
}
50805112

50815113
fn stmt_let(
@@ -5097,6 +5129,11 @@ impl<'a> LoweringContext<'a> {
50975129
)
50985130
}
50995131

5132+
fn expr_block_empty(&mut self, span: Span) -> hir::Expr {
5133+
let blk = self.block_all(span, hir_vec![], None);
5134+
self.expr_block(P(blk), ThinVec::new())
5135+
}
5136+
51005137
fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
51015138
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
51025139
}
@@ -5119,6 +5156,13 @@ impl<'a> LoweringContext<'a> {
51195156
}
51205157
}
51215158

5159+
/// Constructs a `true` or `false` literal pattern.
5160+
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
5161+
let lit = Spanned { span, node: LitKind::Bool(val) };
5162+
let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new());
5163+
self.pat(span, hir::PatKind::Lit(P(expr)))
5164+
}
5165+
51225166
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
51235167
self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
51245168
}
@@ -5209,6 +5253,18 @@ impl<'a> LoweringContext<'a> {
52095253
path
52105254
}
52115255

5256+
/*
5257+
/// Constructs and returns the type `bool`.
5258+
fn ty_bool(&mut self, span: Span) -> hir::Ty {
5259+
let id = self.next_id();
5260+
self.ty_path(id, span, hir::QPath::Resolved(None, P(hir::Path {
5261+
span,
5262+
segments: hir_vec![],
5263+
def: Def::PrimTy(hir::PrimTy::Bool)
5264+
})))
5265+
}
5266+
*/
5267+
52125268
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> hir::Ty {
52135269
let mut id = id;
52145270
let node = match qpath {

src/librustc/hir/mod.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ impl Expr {
13661366
ExprKind::Unary(..) => ExprPrecedence::Unary,
13671367
ExprKind::Lit(_) => ExprPrecedence::Lit,
13681368
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
1369-
ExprKind::If(..) => ExprPrecedence::If,
1369+
ExprKind::Use(ref expr, ..) => expr.precedence(),
13701370
ExprKind::While(..) => ExprPrecedence::While,
13711371
ExprKind::Loop(..) => ExprPrecedence::Loop,
13721372
ExprKind::Match(..) => ExprPrecedence::Match,
@@ -1416,7 +1416,6 @@ impl Expr {
14161416
ExprKind::MethodCall(..) |
14171417
ExprKind::Struct(..) |
14181418
ExprKind::Tup(..) |
1419-
ExprKind::If(..) |
14201419
ExprKind::Match(..) |
14211420
ExprKind::Closure(..) |
14221421
ExprKind::Block(..) |
@@ -1437,6 +1436,7 @@ impl Expr {
14371436
ExprKind::Binary(..) |
14381437
ExprKind::Yield(..) |
14391438
ExprKind::Cast(..) |
1439+
ExprKind::Use(..) |
14401440
ExprKind::Err => {
14411441
false
14421442
}
@@ -1486,10 +1486,10 @@ pub enum ExprKind {
14861486
Cast(P<Expr>, P<Ty>),
14871487
/// A type reference (e.g., `Foo`).
14881488
Type(P<Expr>, P<Ty>),
1489-
/// An `if` block, with an optional else block.
1490-
///
1491-
/// I.e., `if <expr> { <expr> } else { <expr> }`.
1492-
If(P<Expr>, P<Expr>, Option<P<Expr>>),
1489+
/// Equivalent to `{ let _t = expr; _t }`.
1490+
/// Maps directly to `hair::ExprKind::Use`.
1491+
/// Only exists to tweak the drop order in HIR.
1492+
Use(P<Expr>),
14931493
/// A while loop, with an optional label
14941494
///
14951495
/// I.e., `'label: while expr { <block> }`.
@@ -1590,6 +1590,10 @@ pub enum LocalSource {
15901590
pub enum MatchSource {
15911591
/// A `match _ { .. }`.
15921592
Normal,
1593+
/// An `if _ { .. }` (optionally with `else { .. }`).
1594+
IfDesugar {
1595+
contains_else_clause: bool,
1596+
},
15931597
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
15941598
IfLetDesugar {
15951599
contains_else_clause: bool,

0 commit comments

Comments
 (0)