Skip to content

Commit c9fb639

Browse files
committed
let_chains: Adjust lowering logic in lieu of ::Let.
1 parent a7b00f5 commit c9fb639

File tree

1 file changed

+106
-138
lines changed

1 file changed

+106
-138
lines changed

src/librustc/hir/lowering.rs

Lines changed: 106 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,53 +4344,120 @@ impl<'a> LoweringContext<'a> {
43444344
let ohs = P(self.lower_expr(ohs));
43454345
hir::ExprKind::AddrOf(m, ohs)
43464346
}
4347-
// More complicated than you might expect because the else branch
4348-
// might be `if let`.
4347+
ExprKind::Let(..) => {
4348+
// This should have been caught `ast_validation`!
4349+
self.sess.span_err(e.span, "`let` expressions only supported in `if`");
4350+
// ^-- FIXME(53667): Change to `delay_span_bug` when let_chains handled in lowering.
4351+
self.sess.abort_if_errors();
4352+
hir::ExprKind::Err
4353+
}
4354+
// FIXME(#53667): handle lowering of && and parens.
43494355
ExprKind::If(ref cond, ref then, ref else_opt) => {
4350-
// `true => then`:
4351-
let then_pat = self.pat_bool(e.span, true);
4352-
let then_blk = self.lower_block(then, false);
4353-
let then_expr = self.expr_block(then_blk, ThinVec::new());
4354-
let then_arm = self.arm(hir_vec![then_pat], P(then_expr));
4355-
43564356
// `_ => else_block` where `else_block` is `{}` if there's `None`:
43574357
let else_pat = self.pat_wild(e.span);
4358-
let else_expr = match else_opt {
4359-
None => self.expr_block_empty(e.span),
4360-
Some(els) => match els.node {
4361-
ExprKind::IfLet(..) => {
4362-
// Wrap the `if let` expr in a block.
4363-
let els = self.lower_expr(els);
4364-
let blk = self.block_all(els.span, hir_vec![], Some(P(els)));
4365-
self.expr_block(P(blk), ThinVec::new())
4366-
}
4367-
_ => self.lower_expr(els),
4368-
}
4358+
let (else_expr, contains_else_clause) = match else_opt {
4359+
None => (self.expr_block_empty(e.span), false),
4360+
Some(els) => (self.lower_expr(els), true),
43694361
};
43704362
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
43714363

4372-
// Lower condition:
4373-
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
4374-
let cond = self.lower_expr(cond);
4375-
// Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
4376-
// semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
4377-
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
4364+
// Handle then + scrutinee:
4365+
let then_blk = self.lower_block(then, false);
4366+
let then_expr = self.expr_block(then_blk, ThinVec::new());
4367+
let (then_pats, scrutinee, desugar) = match cond.node {
4368+
// `<pat> => <then>`
4369+
ExprKind::Let(ref pats, ref scrutinee) => {
4370+
let scrutinee = self.lower_expr(scrutinee);
4371+
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
4372+
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
4373+
(pats, scrutinee, desugar)
4374+
}
4375+
// `true => then`:
4376+
_ => {
4377+
// Lower condition:
4378+
let cond = self.lower_expr(cond);
4379+
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4380+
// to preserve drop semantics since `if cond { ... }`
4381+
// don't let temporaries live outside of `cond`.
4382+
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
4383+
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4384+
// to preserve drop semantics since `if cond { ... }` does not
4385+
// let temporaries live outside of `cond`.
4386+
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
4387+
4388+
let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
4389+
let pats = hir_vec![self.pat_bool(e.span, true)];
4390+
(pats, cond, desugar)
4391+
}
4392+
};
4393+
let then_arm = self.arm(then_pats, P(then_expr));
43784394

4379-
hir::ExprKind::Match(
4380-
P(cond),
4381-
vec![then_arm, else_arm].into(),
4382-
hir::MatchSource::IfDesugar {
4383-
contains_else_clause: else_opt.is_some()
4384-
},
4385-
)
4395+
hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
4396+
}
4397+
// FIXME(#53667): handle lowering of && and parens.
4398+
ExprKind::While(ref cond, ref body, opt_label) => {
4399+
// Desugar `ExprWhileLet`
4400+
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
4401+
if let ExprKind::Let(ref pats, ref sub_expr) = cond.node {
4402+
// to:
4403+
//
4404+
// [opt_ident]: loop {
4405+
// match <sub_expr> {
4406+
// <pat> => <body>,
4407+
// _ => break
4408+
// }
4409+
// }
4410+
4411+
// Note that the block AND the condition are evaluated in the loop scope.
4412+
// This is done to allow `break` from inside the condition of the loop.
4413+
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
4414+
(
4415+
this.lower_block(body, false),
4416+
this.expr_break(e.span, ThinVec::new()),
4417+
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
4418+
)
4419+
});
4420+
4421+
// `<pat> => <body>`
4422+
let pat_arm = {
4423+
let body_expr = P(self.expr_block(body, ThinVec::new()));
4424+
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
4425+
self.arm(pats, body_expr)
4426+
};
4427+
4428+
// `_ => break`
4429+
let break_arm = {
4430+
let pat_under = self.pat_wild(e.span);
4431+
self.arm(hir_vec![pat_under], break_expr)
4432+
};
4433+
4434+
// `match <sub_expr> { ... }`
4435+
let arms = hir_vec![pat_arm, break_arm];
4436+
let match_expr = self.expr(
4437+
sub_expr.span,
4438+
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
4439+
ThinVec::new(),
4440+
);
4441+
4442+
// `[opt_ident]: loop { ... }`
4443+
let loop_block = P(self.block_expr(P(match_expr)));
4444+
let loop_expr = hir::ExprKind::Loop(
4445+
loop_block,
4446+
self.lower_label(opt_label),
4447+
hir::LoopSource::WhileLet,
4448+
);
4449+
// Add attributes to the outer returned expr node.
4450+
loop_expr
4451+
} else {
4452+
self.with_loop_scope(e.id, |this| {
4453+
hir::ExprKind::While(
4454+
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
4455+
this.lower_block(body, false),
4456+
this.lower_label(opt_label),
4457+
)
4458+
})
4459+
}
43864460
}
4387-
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
4388-
hir::ExprKind::While(
4389-
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
4390-
this.lower_block(body, false),
4391-
this.lower_label(opt_label),
4392-
)
4393-
}),
43944461
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
43954462
hir::ExprKind::Loop(
43964463
this.lower_block(body, false),
@@ -4703,105 +4770,6 @@ impl<'a> LoweringContext<'a> {
47034770

47044771
ExprKind::Err => hir::ExprKind::Err,
47054772

4706-
// Desugar `ExprIfLet`
4707-
// from: `if let <pat> = <sub_expr> <body> [<else_opt>]`
4708-
ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
4709-
// to:
4710-
//
4711-
// match <sub_expr> {
4712-
// <pat> => <body>,
4713-
// _ => [<else_opt> | ()]
4714-
// }
4715-
4716-
let mut arms = vec![];
4717-
4718-
// `<pat> => <body>`
4719-
{
4720-
let body = self.lower_block(body, false);
4721-
let body_expr = P(self.expr_block(body, ThinVec::new()));
4722-
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
4723-
arms.push(self.arm(pats, body_expr));
4724-
}
4725-
4726-
// _ => [<else_opt>|{}]
4727-
{
4728-
let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
4729-
let wildcard_pattern = self.pat_wild(e.span);
4730-
let body = if let Some(else_expr) = wildcard_arm {
4731-
self.lower_expr(else_expr)
4732-
} else {
4733-
self.expr_block_empty(e.span)
4734-
};
4735-
arms.push(self.arm(hir_vec![wildcard_pattern], P(body)));
4736-
}
4737-
4738-
let contains_else_clause = else_opt.is_some();
4739-
4740-
let sub_expr = P(self.lower_expr(sub_expr));
4741-
4742-
hir::ExprKind::Match(
4743-
sub_expr,
4744-
arms.into(),
4745-
hir::MatchSource::IfLetDesugar {
4746-
contains_else_clause,
4747-
},
4748-
)
4749-
}
4750-
4751-
// Desugar `ExprWhileLet`
4752-
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
4753-
ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
4754-
// to:
4755-
//
4756-
// [opt_ident]: loop {
4757-
// match <sub_expr> {
4758-
// <pat> => <body>,
4759-
// _ => break
4760-
// }
4761-
// }
4762-
4763-
// Note that the block AND the condition are evaluated in the loop scope.
4764-
// This is done to allow `break` from inside the condition of the loop.
4765-
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
4766-
(
4767-
this.lower_block(body, false),
4768-
this.expr_break(e.span, ThinVec::new()),
4769-
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
4770-
)
4771-
});
4772-
4773-
// `<pat> => <body>`
4774-
let pat_arm = {
4775-
let body_expr = P(self.expr_block(body, ThinVec::new()));
4776-
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
4777-
self.arm(pats, body_expr)
4778-
};
4779-
4780-
// `_ => break`
4781-
let break_arm = {
4782-
let pat_under = self.pat_wild(e.span);
4783-
self.arm(hir_vec![pat_under], break_expr)
4784-
};
4785-
4786-
// `match <sub_expr> { ... }`
4787-
let arms = hir_vec![pat_arm, break_arm];
4788-
let match_expr = self.expr(
4789-
sub_expr.span,
4790-
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
4791-
ThinVec::new(),
4792-
);
4793-
4794-
// `[opt_ident]: loop { ... }`
4795-
let loop_block = P(self.block_expr(P(match_expr)));
4796-
let loop_expr = hir::ExprKind::Loop(
4797-
loop_block,
4798-
self.lower_label(opt_label),
4799-
hir::LoopSource::WhileLet,
4800-
);
4801-
// Add attributes to the outer returned expr node.
4802-
loop_expr
4803-
}
4804-
48054773
// Desugar `ExprForLoop`
48064774
// from: `[opt_ident]: for <pat> in <head> <body>`
48074775
ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {

0 commit comments

Comments
 (0)