Lowering: Fuse ExprKind::While logic + Cleanup.

This commit is contained in:
Mazdak Farrokhzad 2019-06-23 18:58:36 +02:00
parent 547735457f
commit 26144fe869
1 changed files with 54 additions and 85 deletions

View File

@ -4394,20 +4394,17 @@ impl<'a> LoweringContext<'a> {
let then_blk = self.lower_block(then, false); let then_blk = self.lower_block(then, false);
let then_expr = self.expr_block(then_blk, ThinVec::new()); let then_expr = self.expr_block(then_blk, ThinVec::new());
let (then_pats, scrutinee, desugar) = match cond.node { let (then_pats, scrutinee, desugar) = match cond.node {
// `<pat> => <then>` // `<pat> => <then>`:
ExprKind::Let(ref pats, ref scrutinee) => { ExprKind::Let(ref pats, ref scrutinee) => {
let scrutinee = self.lower_expr(scrutinee); let scrutinee = self.lower_expr(scrutinee);
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
(pats, scrutinee, desugar) (pats, scrutinee, desugar)
} }
// `true => then`: // `true => <then>`:
_ => { _ => {
// Lower condition: // Lower condition:
let cond = self.lower_expr(cond); 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(CondTemporary, 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 }` // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `if cond { ... }` does not // to preserve drop semantics since `if cond { ... }` does not
@ -4424,61 +4421,36 @@ impl<'a> LoweringContext<'a> {
hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
} }
// FIXME(#53667): handle lowering of && and parens. // FIXME(#53667): handle lowering of && and parens.
ExprKind::While(ref cond, ref body, opt_label) => { ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
// Desugar `ExprWhileLet` // Note that the block AND the condition are evaluated in the loop scope.
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>` // This is done to allow `break` from inside the condition of the loop.
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. // `_ => break`:
// This is done to allow `break` from inside the condition of the loop. let else_arm = {
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| { let else_pat = this.pat_wild(e.span);
( let else_expr = this.expr_break(e.span, ThinVec::new());
this.lower_block(body, false), this.arm(hir_vec![else_pat], else_expr)
this.expr_break(e.span, ThinVec::new()), };
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
)
});
// `<pat> => <body>` // Handle then + scrutinee:
let pat_arm = { let then_blk = this.lower_block(body, false);
let body_expr = P(self.expr_block(body, ThinVec::new())); let then_expr = this.expr_block(then_blk, ThinVec::new());
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); let (then_pats, scrutinee, desugar, source) = match cond.node {
self.arm(pats, body_expr) ExprKind::Let(ref pats, ref scrutinee) => {
}; // to:
//
// `_ => break` // [opt_ident]: loop {
let break_arm = { // match <sub_expr> {
let pat_under = self.pat_wild(e.span); // <pat> => <body>,
self.arm(hir_vec![pat_under], break_expr) // _ => break
}; // }
// }
// `match <sub_expr> { ... }` let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
let match_expr = self.expr_match( let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect();
sub_expr.span, let desugar = hir::MatchSource::WhileLetDesugar;
sub_expr, (pats, scrutinee, desugar, hir::LoopSource::WhileLet)
hir_vec![pat_arm, break_arm], }
hir::MatchSource::WhileLetDesugar, _ => {
);
// `[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| {
// We desugar: `'label: while $cond $body` into: // We desugar: `'label: while $cond $body` into:
// //
// ``` // ```
@ -4490,40 +4462,37 @@ impl<'a> LoweringContext<'a> {
// } // }
// ``` // ```
// `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: // Lower condition:
let span_block = this.mark_span_with_reason(CondTemporary, cond.span, None);
let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond)); 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 }` // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `if cond { ... }` does not // to preserve drop semantics since `while cond { ... }` does not
// let temporaries live outside of `cond`. // let temporaries live outside of `cond`.
let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new()); let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new());
let match_expr = this.expr_match( let desugar = hir::MatchSource::WhileDesugar;
cond.span, // `true => <then>`:
P(cond), let pats = hir_vec![this.pat_bool(e.span, true)];
vec![then_arm, else_arm].into(), (pats, cond, desugar, hir::LoopSource::While)
hir::MatchSource::WhileDesugar, }
); };
let then_arm = this.arm(then_pats, P(then_expr));
hir::ExprKind::Loop( // `match <scrutinee> { ... }`
P(this.block_expr(P(match_expr))), let match_expr = this.expr_match(
this.lower_label(opt_label), scrutinee.span,
hir::LoopSource::While, 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| { ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::Loop( hir::ExprKind::Loop(
this.lower_block(body, false), this.lower_block(body, false),