diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-05-15 16:05:05 +0200 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-06-23 01:29:29 +0200 |
| commit | c9fb6390859bb1d2aca957528c121c2f99b74f42 (patch) | |
| tree | 2216e620b895b1f9839b5e39421d55b903b3a80c | |
| parent | a7b00f5807dc02f9990c649572d76a91a850110c (diff) | |
| download | rust-c9fb6390859bb1d2aca957528c121c2f99b74f42.tar.gz rust-c9fb6390859bb1d2aca957528c121c2f99b74f42.zip | |
let_chains: Adjust lowering logic in lieu of ::Let.
| -rw-r--r-- | src/librustc/hir/lowering.rs | 244 |
1 files changed, 106 insertions, 138 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c87ab686937..a684816c6de 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4344,53 +4344,120 @@ impl<'a> LoweringContext<'a> { let ohs = P(self.lower_expr(ohs)); hir::ExprKind::AddrOf(m, ohs) } - // More complicated than you might expect because the else branch - // might be `if let`. + ExprKind::Let(..) => { + // This should have been caught `ast_validation`! + self.sess.span_err(e.span, "`let` expressions only supported in `if`"); + // ^-- FIXME(53667): Change to `delay_span_bug` when let_chains handled in lowering. + self.sess.abort_if_errors(); + hir::ExprKind::Err + } + // FIXME(#53667): handle lowering of && and parens. 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 els = self.lower_expr(els); - let blk = self.block_all(els.span, hir_vec![], Some(P(els))); - self.expr_block(P(blk), ThinVec::new()) - } - _ => self.lower_expr(els), - } + let (else_expr, contains_else_clause) = match else_opt { + None => (self.expr_block_empty(e.span), false), + Some(els) => (self.lower_expr(els), true), }; let else_arm = self.arm(hir_vec![else_pat], P(else_expr)); - // Lower condition: - let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None); - 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 cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); + // Handle then + scrutinee: + let then_blk = self.lower_block(then, false); + let then_expr = self.expr_block(then_blk, ThinVec::new()); + let (then_pats, scrutinee, desugar) = match cond.node { + // `<pat> => <then>` + ExprKind::Let(ref pats, ref scrutinee) => { + let scrutinee = self.lower_expr(scrutinee); + let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); + let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; + (pats, scrutinee, desugar) + } + // `true => then`: + _ => { + // Lower condition: + 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(IfTemporary, 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, P(cond), ThinVec::new()); + + let desugar = hir::MatchSource::IfDesugar { contains_else_clause }; + let pats = hir_vec![self.pat_bool(e.span, true)]; + (pats, cond, desugar) + } + }; + let then_arm = self.arm(then_pats, P(then_expr)); - hir::ExprKind::Match( - P(cond), - vec![then_arm, else_arm].into(), - hir::MatchSource::IfDesugar { - contains_else_clause: else_opt.is_some() - }, - ) + hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) + } + // FIXME(#53667): handle lowering of && and parens. + ExprKind::While(ref cond, ref body, opt_label) => { + // Desugar `ExprWhileLet` + // from: `[opt_ident]: while let <pat> = <sub_expr> <body>` + 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. + // This is done to allow `break` from inside the condition of the loop. + let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| { + ( + this.lower_block(body, false), + this.expr_break(e.span, ThinVec::new()), + this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), + ) + }); + + // `<pat> => <body>` + let pat_arm = { + let body_expr = P(self.expr_block(body, ThinVec::new())); + let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); + self.arm(pats, body_expr) + }; + + // `_ => break` + let break_arm = { + let pat_under = self.pat_wild(e.span); + self.arm(hir_vec![pat_under], break_expr) + }; + + // `match <sub_expr> { ... }` + let arms = hir_vec![pat_arm, break_arm]; + let match_expr = self.expr( + sub_expr.span, + hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar), + ThinVec::new(), + ); + + // `[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| { + hir::ExprKind::While( + this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), + this.lower_block(body, false), + this.lower_label(opt_label), + ) + }) + } } - ExprKind::While(ref cond, ref body, opt_label) => 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), - this.lower_label(opt_label), - ) - }), ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { hir::ExprKind::Loop( this.lower_block(body, false), @@ -4703,105 +4770,6 @@ impl<'a> LoweringContext<'a> { ExprKind::Err => hir::ExprKind::Err, - // Desugar `ExprIfLet` - // from: `if let <pat> = <sub_expr> <body> [<else_opt>]` - ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => { - // to: - // - // match <sub_expr> { - // <pat> => <body>, - // _ => [<else_opt> | ()] - // } - - let mut arms = vec![]; - - // `<pat> => <body>` - { - let body = self.lower_block(body, false); - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - arms.push(self.arm(pats, body_expr)); - } - - // _ => [<else_opt>|{}] - { - let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); - let wildcard_pattern = self.pat_wild(e.span); - let body = if let Some(else_expr) = wildcard_arm { - self.lower_expr(else_expr) - } else { - self.expr_block_empty(e.span) - }; - arms.push(self.arm(hir_vec![wildcard_pattern], P(body))); - } - - let contains_else_clause = else_opt.is_some(); - - let sub_expr = P(self.lower_expr(sub_expr)); - - hir::ExprKind::Match( - sub_expr, - arms.into(), - hir::MatchSource::IfLetDesugar { - contains_else_clause, - }, - ) - } - - // Desugar `ExprWhileLet` - // from: `[opt_ident]: while let <pat> = <sub_expr> <body>` - ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => { - // to: - // - // [opt_ident]: loop { - // match <sub_expr> { - // <pat> => <body>, - // _ => break - // } - // } - - // Note that the block AND the condition are evaluated in the loop scope. - // This is done to allow `break` from inside the condition of the loop. - let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| { - ( - this.lower_block(body, false), - this.expr_break(e.span, ThinVec::new()), - this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), - ) - }); - - // `<pat> => <body>` - let pat_arm = { - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - self.arm(pats, body_expr) - }; - - // `_ => break` - let break_arm = { - let pat_under = self.pat_wild(e.span); - self.arm(hir_vec![pat_under], break_expr) - }; - - // `match <sub_expr> { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let match_expr = self.expr( - sub_expr.span, - hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar), - ThinVec::new(), - ); - - // `[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 - } - // Desugar `ExprForLoop` // from: `[opt_ident]: for <pat> in <head> <body>` ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { |
