Skip to content

Commit deed92a

Browse files
committed
let_chains: adjust for 'while let'
1 parent 7b69082 commit deed92a

File tree

10 files changed

+82
-140
lines changed

10 files changed

+82
-140
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ pub(super) fn note_and_explain_region(
100100
Some(Node::Expr(expr)) => match expr.kind {
101101
hir::ExprKind::Call(..) => "call",
102102
hir::ExprKind::MethodCall(..) => "method call",
103-
hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
104-
hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
103+
hir::ExprKind::Match(.., hir::MatchSource::IfDesugar { .. }) => "if",
104+
hir::ExprKind::Match(.., hir::MatchSource::WhileDesugar) => "while",
105105
hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
106106
hir::ExprKind::Match(..) => "match",
107107
_ => "expression",
@@ -610,10 +610,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
610610
scrut_hir_id,
611611
..
612612
}) => match source {
613-
hir::MatchSource::IfLetDesugar { .. } => {
614-
let msg = "`if let` arms have incompatible types";
615-
err.span_label(cause.span, msg);
616-
}
617613
hir::MatchSource::TryDesugar => {
618614
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
619615
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
@@ -1985,9 +1981,6 @@ impl<'tcx> ObligationCause<'tcx> {
19851981
CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
19861982
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
19871983
Error0308(match source {
1988-
hir::MatchSource::IfLetDesugar { .. } => {
1989-
"`if let` arms have incompatible types"
1990-
}
19911984
hir::MatchSource::TryDesugar => {
19921985
"try expression alternatives have incompatible types"
19931986
}
@@ -2023,10 +2016,7 @@ impl<'tcx> ObligationCause<'tcx> {
20232016
CompareImplMethodObligation { .. } => "method type is compatible with trait",
20242017
CompareImplTypeObligation { .. } => "associated type is compatible with trait",
20252018
ExprAssignable => "expression is assignable",
2026-
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
2027-
hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
2028-
_ => "`match` arms have compatible types",
2029-
},
2019+
MatchExpressionArm(_) => "`match` arms have compatible types",
20302020
IfExpression { .. } => "`if` and `else` have incompatible types",
20312021
IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
20322022
MainFunctionType => "`main` function has the correct type",

src/librustc_ast_lowering/expr.rs

Lines changed: 55 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -245,120 +245,92 @@ impl<'hir> LoweringContext<'_, 'hir> {
245245
}
246246
}
247247

248-
fn lower_expr_if(
249-
&mut self,
250-
span: Span,
251-
cond: &Expr,
252-
then: &Block,
253-
else_opt: Option<&Expr>,
254-
) -> hir::ExprKind<'hir> {
248+
/// Lower the condition of an `if` or `while` expression.
249+
/// This entails some special handling of immediate `let` expressions as conditions.
250+
/// Namely, if the given `cond` is not a `let` expression then it is wrapped in `drop-temps`.
251+
fn lower_expr_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> {
255252
// Lower the `cond` expression.
256-
let cond_expr = self.lower_expr(cond);
253+
let cond = self.lower_expr(cond);
257254
// Normally, the `cond` of `if cond` will drop temporaries before evaluating the blocks.
258255
// This is achieved by using `drop-temps { cond }`, equivalent to `{ let _t = $cond; _t }`.
259256
// However, for backwards compatibility reasons, `if let pat = scrutinee`, like `match`
260257
// does not drop the temporaries of `scrutinee` before evaluating the blocks.
261-
let contains_else_clause = else_opt.is_some();
262-
let (scrutinee, desugar) = match cond.kind {
263-
ExprKind::Let(..) => {
264-
(cond_expr, hir::MatchSource::IfLetDesugar { contains_else_clause })
265-
}
258+
match cond.kind {
259+
hir::ExprKind::Let(..) => cond,
266260
_ => {
267-
let span =
268-
self.mark_span_with_reason(DesugaringKind::CondTemporary, cond_expr.span, None);
269-
let cond_expr = self.expr_drop_temps(span, cond_expr, ThinVec::new());
270-
(cond_expr, hir::MatchSource::IfDesugar { contains_else_clause })
261+
let reason = DesugaringKind::CondTemporary;
262+
let span = self.mark_span_with_reason(reason, cond.span, None);
263+
self.expr_drop_temps(span, cond, ThinVec::new())
271264
}
272-
};
265+
}
266+
}
273267

274-
// `true => $then`:
268+
/// Lower `then` into `true => then`.
269+
fn lower_then_arm(&mut self, span: Span, then: &Block) -> hir::Arm<'hir> {
275270
let then_expr = self.lower_block_expr(then);
276271
let then_pat = self.pat_bool(span, true);
277-
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
272+
self.arm(then_pat, self.arena.alloc(then_expr))
273+
}
278274

279-
// `_ => else_block` where `else_block` is `{}` if there's `None`:
275+
fn lower_else_arm(&mut self, span: Span, else_expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> {
280276
let else_pat = self.pat_wild(span);
277+
self.arm(else_pat, else_expr)
278+
}
279+
280+
fn lower_expr_if(
281+
&mut self,
282+
span: Span,
283+
cond: &Expr,
284+
then: &Block,
285+
else_opt: Option<&Expr>,
286+
) -> hir::ExprKind<'hir> {
287+
let scrutinee = self.lower_expr_cond(cond);
288+
let then_arm = self.lower_then_arm(span, then);
281289
let else_expr = match else_opt {
282-
None => self.expr_block_empty(span),
290+
None => self.expr_block_empty(span), // Use `{}` if there's no `else` block.
283291
Some(els) => self.lower_expr(els),
284292
};
285-
let else_arm = self.arm(else_pat, else_expr);
286-
293+
let else_arm = self.lower_else_arm(span, else_expr);
294+
let desugar = hir::MatchSource::IfDesugar { contains_else_clause: else_opt.is_some() };
287295
hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar)
288296
}
289297

298+
/// We desugar: `'label: while $cond $body` into:
299+
///
300+
/// ```
301+
/// 'label: loop {
302+
/// match $cond {
303+
/// true => $body,
304+
/// _ => break,
305+
/// }
306+
/// }
307+
/// ```
308+
///
309+
/// where `$cond` is wrapped in `drop-temps { $cond }` if it isn't a `Let` expression.
290310
fn lower_expr_while_in_loop_scope(
291311
&mut self,
292312
span: Span,
293313
cond: &Expr,
294314
body: &Block,
295315
opt_label: Option<Label>,
296316
) -> hir::ExprKind<'hir> {
297-
// FIXME(#53667): handle lowering of && and parens.
298-
299317
// Note that the block AND the condition are evaluated in the loop scope.
300318
// This is done to allow `break` from inside the condition of the loop.
301319

320+
// Lower the condition:
321+
let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr_cond(cond));
322+
// `true => body`:
323+
let then_arm = self.lower_then_arm(span, body);
302324
// `_ => break`:
303-
let else_arm = {
304-
let else_pat = self.pat_wild(span);
305-
let else_expr = self.expr_break(span, ThinVec::new());
306-
self.arm(else_pat, else_expr)
307-
};
308-
309-
// Handle then + scrutinee:
310-
let then_expr = self.lower_block_expr(body);
311-
let (then_pat, scrutinee, desugar, source) = match cond.kind {
312-
ExprKind::Let(ref pat, ref scrutinee) => {
313-
// to:
314-
//
315-
// [opt_ident]: loop {
316-
// match <sub_expr> {
317-
// <pat> => <body>,
318-
// _ => break
319-
// }
320-
// }
321-
let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
322-
let pat = self.lower_pat(pat);
323-
(pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
324-
}
325-
_ => {
326-
// We desugar: `'label: while $cond $body` into:
327-
//
328-
// ```
329-
// 'label: loop {
330-
// match drop-temps { $cond } {
331-
// true => $body,
332-
// _ => break,
333-
// }
334-
// }
335-
// ```
336-
337-
// Lower condition:
338-
let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond));
339-
let span_block =
340-
self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
341-
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
342-
// to preserve drop semantics since `while cond { ... }` does not
343-
// let temporaries live outside of `cond`.
344-
let cond = self.expr_drop_temps(span_block, cond, ThinVec::new());
345-
// `true => <then>`:
346-
let pat = self.pat_bool(span, true);
347-
(pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
348-
}
349-
};
350-
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
351-
325+
let else_expr = self.expr_break(span, ThinVec::new());
326+
let else_arm = self.lower_else_arm(span, else_expr);
352327
// `match <scrutinee> { ... }`
353-
let match_expr = self.expr_match(
354-
scrutinee.span,
355-
scrutinee,
356-
arena_vec![self; then_arm, else_arm],
357-
desugar,
358-
);
359-
328+
let match_arms = arena_vec![self; then_arm, else_arm];
329+
let match_desugar = hir::MatchSource::WhileDesugar;
330+
let match_expr = self.expr_match(scrutinee.span, scrutinee, match_arms, match_desugar);
360331
// `[opt_ident]: loop { ... }`
361-
hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source)
332+
let loop_block = self.block_expr(self.arena.alloc(match_expr));
333+
hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::While)
362334
}
363335

364336
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,

src/librustc_hir/hir.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,13 +1686,8 @@ pub enum MatchSource {
16861686
Normal,
16871687
/// An `if _ { .. }` (optionally with `else { .. }`).
16881688
IfDesugar { contains_else_clause: bool },
1689-
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
1690-
IfLetDesugar { contains_else_clause: bool },
16911689
/// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
16921690
WhileDesugar,
1693-
/// A `while let _ = _ { .. }` (which was desugared to a
1694-
/// `loop { match _ { .. } }`).
1695-
WhileLetDesugar,
16961691
/// A desugared `for _ in _ { .. }` loop.
16971692
ForLoopDesugar,
16981693
/// A desugared `?` operator.
@@ -1706,8 +1701,8 @@ impl MatchSource {
17061701
use MatchSource::*;
17071702
match self {
17081703
Normal => "match",
1709-
IfDesugar { .. } | IfLetDesugar { .. } => "if",
1710-
WhileDesugar | WhileLetDesugar => "while",
1704+
IfDesugar { .. } => "if",
1705+
WhileDesugar => "while",
17111706
ForLoopDesugar => "for",
17121707
TryDesugar => "?",
17131708
AwaitDesugar => ".await",
@@ -1722,8 +1717,6 @@ pub enum LoopSource {
17221717
Loop,
17231718
/// A `while _ { .. }` loop.
17241719
While,
1725-
/// A `while let _ = _ { .. }` loop.
1726-
WhileLet,
17271720
/// A `for _ in _ { .. }` loop.
17281721
ForLoop,
17291722
}
@@ -1732,7 +1725,7 @@ impl LoopSource {
17321725
pub fn name(self) -> &'static str {
17331726
match self {
17341727
LoopSource::Loop => "loop",
1735-
LoopSource::While | LoopSource::WhileLet => "while",
1728+
LoopSource::While => "while",
17361729
LoopSource::ForLoop => "for",
17371730
}
17381731
}

src/librustc_mir_build/hair/cx/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
476476
hir::ExprKind::Match(
477477
hir::Expr { kind: hir::ExprKind::Let(ref pat, ref scrutinee), .. },
478478
[ref then_arm, ref else_arm],
479-
hir::MatchSource::IfLetDesugar { .. },
479+
_,
480480
) => {
481481
// HACK(let_chains, Centril): This is the desugaring for `if let`.
482482
// We do not yet have `hair::ExprKind::Let`.

src/librustc_mir_build/hair/pattern/check_match.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
158158
let wild = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(pattern.ty));
159159
wild.span = pattern.span;
160160
let arms = &[(pattern, pat.hir_id, false), (wild, pat.hir_id, false)];
161-
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause: true };
161+
let desugar = hir::MatchSource::IfDesugar { contains_else_clause: true };
162162
self.check_union_irrefutable(cx, scrut, arms, desugar)
163163
});
164164
}
@@ -364,8 +364,9 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
364364

365365
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
366366
let msg = match source {
367-
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
368-
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
367+
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => {
368+
"irrefutable `let` pattern"
369+
}
369370
_ => bug!(),
370371
};
371372
tcx.lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, msg);
@@ -384,9 +385,7 @@ fn check_arms<'p, 'tcx>(
384385
match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) {
385386
NotUseful => {
386387
match source {
387-
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
388-
389-
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
388+
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => {
390389
// Check which arm we're on.
391390
match arm_index {
392391
// The arm with the user-specified pattern.

src/librustc_passes/check_const.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,13 @@ impl NonConstExpr {
4343
use hir::MatchSource::*;
4444

4545
let gates: &[_] = match self {
46-
Self::Match(Normal)
47-
| Self::Match(IfDesugar { .. })
48-
| Self::Match(IfLetDesugar { .. })
49-
| Self::OrPattern => &[sym::const_if_match],
50-
46+
Self::Match(Normal) | Self::Match(IfDesugar { .. }) | Self::OrPattern => {
47+
&[sym::const_if_match]
48+
}
5149
Self::Loop(Loop) => &[sym::const_loop],
52-
53-
Self::Loop(While)
54-
| Self::Loop(WhileLet)
55-
| Self::Match(WhileDesugar)
56-
| Self::Match(WhileLetDesugar) => &[sym::const_loop, sym::const_if_match],
57-
50+
Self::Loop(While) | Self::Match(WhileDesugar) => {
51+
&[sym::const_loop, sym::const_if_match]
52+
}
5853
// A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
5954
// so they are not yet allowed with `#![feature(const_loop)]`.
6055
_ => return None,
@@ -236,10 +231,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
236231
hir::ExprKind::Match(_, _, source) => {
237232
let non_const_expr = match source {
238233
// These are handled by `ExprKind::Loop` above.
239-
hir::MatchSource::WhileDesugar
240-
| hir::MatchSource::WhileLetDesugar
241-
| hir::MatchSource::ForLoopDesugar => None,
242-
234+
hir::MatchSource::WhileDesugar | hir::MatchSource::ForLoopDesugar => None,
243235
_ => Some(NonConstExpr::Match(*source)),
244236
};
245237

src/librustc_passes/region.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,9 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
399399
}
400400

401401
hir::ExprKind::Match(
402-
hir::Expr { kind: hir::ExprKind::Let(ref pat, ref scrutinee), .. },
402+
hir::Expr { kind: hir::ExprKind::Let(ref pat, scrutinee), .. },
403403
[ref then_arm, ref else_arm],
404-
hir::MatchSource::IfLetDesugar { .. },
404+
_,
405405
) => {
406406
// HACK(let_chains, Centril): In HAIR lowering we currently adjust this
407407
// to `match scrutinee { pat => then_arm.body, _ => else_arm.body }`.

src/librustc_typeck/check/_match.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1919
) -> Ty<'tcx> {
2020
let tcx = self.tcx;
2121

22-
use hir::MatchSource::*;
2322
let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
24-
IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
25-
IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false),
26-
WhileDesugar => (false, false, true),
23+
hir::MatchSource::IfDesugar { contains_else_clause: e } => (true, !e, true),
24+
hir::MatchSource::WhileDesugar => (false, false, true),
2725
_ => (false, false, false),
2826
};
2927

@@ -183,10 +181,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
183181
arms: &'tcx [hir::Arm<'tcx>],
184182
source: hir::MatchSource,
185183
) {
186-
use hir::MatchSource::*;
187184
let msg = match source {
188-
IfDesugar { .. } | IfLetDesugar { .. } => "block in `if` expression",
189-
WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
185+
hir::MatchSource::IfDesugar { .. } => "block in `if` expression",
186+
hir::MatchSource::WhileDesugar { .. } => "block in `while` expression",
190187
_ => "arm",
191188
};
192189
for arm in arms {

src/librustc_typeck/check/expr.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -822,8 +822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
822822
let coerce_to = expected.coercion_target_type(self, body.span);
823823
Some(CoerceMany::new(coerce_to))
824824
}
825-
826-
hir::LoopSource::While | hir::LoopSource::WhileLet | hir::LoopSource::ForLoop => None,
825+
hir::LoopSource::While | hir::LoopSource::ForLoop => None,
827826
};
828827

829828
let ctxt = BreakableCtxt {

src/librustc_typeck/check/generator_interior.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
250250
ExprKind::Match(
251251
Expr { kind: ExprKind::Let(pat, scrutinee), .. },
252252
[then_arm, else_arm],
253-
hir::MatchSource::IfLetDesugar { .. },
253+
_,
254254
) => {
255255
// HACK(let_chains, Centril): In HAIR lowering we currently adjust this
256256
// to `match scrutinee { pat => then_arm.body, _ => else_arm.body }`.

0 commit comments

Comments
 (0)