@@ -86,32 +86,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
8686 let ohs = self.lower_expr(ohs);
8787 hir::ExprKind::AddrOf(k, m, ohs)
8888 }
89- ExprKind::Let(ref pat, ref scrutinee) => {
90- self.lower_expr_let(e.span, pat, scrutinee)
89+ ExprKind::Let(ref pat, ref scrutinee, span) => {
90+ hir::ExprKind::Let(self.lower_pat(pat), self.lower_expr(scrutinee), span)
91+ }
92+ ExprKind::If(ref cond, ref then, ref else_opt) => {
93+ self.lower_expr_if(cond, then, else_opt.as_deref())
9194 }
92- ExprKind::If(ref cond, ref then, ref else_opt) => match cond.kind {
93- ExprKind::Let(ref pat, ref scrutinee) => {
94- self.lower_expr_if_let(e.span, pat, scrutinee, then, else_opt.as_deref())
95- }
96- ExprKind::Paren(ref paren) => match paren.peel_parens().kind {
97- ExprKind::Let(ref pat, ref scrutinee) => {
98- // A user has written `if (let Some(x) = foo) {`, we want to avoid
99- // confusing them with mentions of nightly features.
100- // If this logic is changed, you will also likely need to touch
101- // `unused::UnusedParens::check_expr`.
102- self.if_let_expr_with_parens(cond, &paren.peel_parens());
103- self.lower_expr_if_let(
104- e.span,
105- pat,
106- scrutinee,
107- then,
108- else_opt.as_deref(),
109- )
110- }
111- _ => self.lower_expr_if(cond, then, else_opt.as_deref()),
112- },
113- _ => self.lower_expr_if(cond, then, else_opt.as_deref()),
114- },
11595 ExprKind::While(ref cond, ref body, opt_label) => self
11696 .with_loop_scope(e.id, |this| {
11797 this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
@@ -368,199 +348,69 @@ impl<'hir> LoweringContext<'_, 'hir> {
368348 hir::ExprKind::Call(f, self.lower_exprs(&real_args))
369349 }
370350
371- fn if_let_expr_with_parens(&mut self, cond: &Expr, paren: &Expr) {
372- let start = cond.span.until(paren.span);
373- let end = paren.span.shrink_to_hi().until(cond.span.shrink_to_hi());
374- self.sess
375- .struct_span_err(
376- vec![start, end],
377- "invalid parentheses around `let` expression in `if let`",
378- )
379- .multipart_suggestion(
380- "`if let` needs to be written without parentheses",
381- vec![(start, String::new()), (end, String::new())],
382- rustc_errors::Applicability::MachineApplicable,
383- )
384- .emit();
385- // Ideally, we'd remove the feature gating of a `let` expression since we are already
386- // complaining about it here, but `feature_gate::check_crate` has already run by now:
387- // self.sess.parse_sess.gated_spans.ungate_last(sym::let_chains, paren.span);
388- }
389-
390- /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into:
391- /// ```rust
392- /// match scrutinee { pats => true, _ => false }
393- /// ```
394- fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind<'hir> {
395- // If we got here, the `let` expression is not allowed.
396-
397- if self.sess.opts.unstable_features.is_nightly_build() {
398- self.sess
399- .struct_span_err(span, "`let` expressions are not supported here")
400- .note(
401- "only supported directly without parentheses in conditions of `if`- and \
402- `while`-expressions, as well as in `let` chains within parentheses",
403- )
404- .emit();
405- } else {
406- self.sess
407- .struct_span_err(span, "expected expression, found statement (`let`)")
408- .note("variable declaration using `let` is a statement")
409- .emit();
410- }
411-
412- // For better recovery, we emit:
413- // ```
414- // match scrutinee { pat => true, _ => false }
415- // ```
416- // While this doesn't fully match the user's intent, it has key advantages:
417- // 1. We can avoid using `abort_if_errors`.
418- // 2. We can typeck both `pat` and `scrutinee`.
419- // 3. `pat` is allowed to be refutable.
420- // 4. The return type of the block is `bool` which seems like what the user wanted.
421- let scrutinee = self.lower_expr(scrutinee);
422- let then_arm = {
423- let pat = self.lower_pat(pat);
424- let expr = self.expr_bool(span, true);
425- self.arm(pat, expr)
426- };
427- let else_arm = {
428- let pat = self.pat_wild(span);
429- let expr = self.expr_bool(span, false);
430- self.arm(pat, expr)
431- };
432- hir::ExprKind::Match(
433- scrutinee,
434- arena_vec![self; then_arm, else_arm],
435- hir::MatchSource::Normal,
436- )
437- }
438-
439351 fn lower_expr_if(
440352 &mut self,
441353 cond: &Expr,
442354 then: &Block,
443355 else_opt: Option<&Expr>,
444356 ) -> hir::ExprKind<'hir> {
445- let cond = self.lower_expr(cond);
446- let wrapped_cond = match cond.kind {
447- hir::ExprKind::Let(..) => cond,
448- _ => self.expr_drop_temps(cond.span, cond, AttrVec::new()),
449- };
357+ let lowered_cond = self.lower_expr(cond);
358+ let new_cond = self.manage_let_cond(lowered_cond);
450359 let then_expr = self.lower_block_expr(then);
451360 if let Some(rslt) = else_opt {
452- hir::ExprKind::If(
453- wrapped_cond,
454- self.arena.alloc(then_expr),
455- Some(self.lower_expr(rslt)),
456- )
361+ hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt)))
457362 } else {
458- hir::ExprKind::If(wrapped_cond , self.arena.alloc(then_expr), None)
363+ hir::ExprKind::If(new_cond , self.arena.alloc(then_expr), None)
459364 }
460365 }
461366
462- fn lower_expr_if_let(
463- &mut self,
464- span: Span,
465- pat: &Pat,
466- scrutinee: &Expr,
467- then: &Block,
468- else_opt: Option<&Expr>,
469- ) -> hir::ExprKind<'hir> {
470- // FIXME(#53667): handle lowering of && and parens.
471-
472- // `_ => else_block` where `else_block` is `{}` if there's `None`:
473- let else_pat = self.pat_wild(span);
474- let (else_expr, contains_else_clause) = match else_opt {
475- None => (self.expr_block_empty(span.shrink_to_hi()), false),
476- Some(els) => (self.lower_expr(els), true),
477- };
478- let else_arm = self.arm(else_pat, else_expr);
479-
480- // Handle then + scrutinee:
481- let scrutinee = self.lower_expr(scrutinee);
482- let then_pat = self.lower_pat(pat);
483-
484- let then_expr = self.lower_block_expr(then);
485- let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
486-
487- let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
488- hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar)
367+ // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
368+ // in a temporary block.
369+ fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
370+ match cond.kind {
371+ hir::ExprKind::Let(..) => cond,
372+ _ => {
373+ let span_block =
374+ self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
375+ self.expr_drop_temps(span_block, cond, AttrVec::new())
376+ }
377+ }
489378 }
490379
380+ // We desugar: `'label: while $cond $body` into:
381+ //
382+ // ```
383+ // 'label: loop {
384+ // if { let _t = $cond; _t } {
385+ // $body
386+ // }
387+ // else {
388+ // break;
389+ // }
390+ // }
391+ // ```
392+ //
393+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
394+ // to preserve drop semantics since `while $cond { ... }` does not
395+ // let temporaries live outside of `cond`.
491396 fn lower_expr_while_in_loop_scope(
492397 &mut self,
493398 span: Span,
494399 cond: &Expr,
495400 body: &Block,
496401 opt_label: Option<Label>,
497402 ) -> hir::ExprKind<'hir> {
498- // FIXME(#53667): handle lowering of && and parens.
499-
500- // Note that the block AND the condition are evaluated in the loop scope.
501- // This is done to allow `break` from inside the condition of the loop.
502-
503- // `_ => break`:
504- let else_arm = {
505- let else_pat = self.pat_wild(span);
506- let else_expr = self.expr_break(span, ThinVec::new());
507- self.arm(else_pat, else_expr)
508- };
509-
510- // Handle then + scrutinee:
511- let (then_pat, scrutinee, desugar, source) = match cond.kind {
512- ExprKind::Let(ref pat, ref scrutinee) => {
513- // to:
514- //
515- // [opt_ident]: loop {
516- // match <sub_expr> {
517- // <pat> => <body>,
518- // _ => break
519- // }
520- // }
521- let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
522- let pat = self.lower_pat(pat);
523- (pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
524- }
525- _ => {
526- // We desugar: `'label: while $cond $body` into:
527- //
528- // ```
529- // 'label: loop {
530- // match drop-temps { $cond } {
531- // true => $body,
532- // _ => break,
533- // }
534- // }
535- // ```
536-
537- // Lower condition:
538- let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond));
539- let span_block =
540- self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
541- // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
542- // to preserve drop semantics since `while cond { ... }` does not
543- // let temporaries live outside of `cond`.
544- let cond = self.expr_drop_temps(span_block, cond, ThinVec::new());
545- // `true => <then>`:
546- let pat = self.pat_bool(span, true);
547- (pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
548- }
549- };
550- let then_expr = self.lower_block_expr(body);
551- let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
552-
553- // `match <scrutinee> { ... }`
554- let match_expr =
555- self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
556-
557- // `[opt_ident]: loop { ... }`
558- hir::ExprKind::Loop(
559- self.block_expr(self.arena.alloc(match_expr)),
560- opt_label,
561- source,
562- span.with_hi(cond.span.hi()),
563- )
403+ let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
404+ let new_cond = self.manage_let_cond(lowered_cond);
405+ let then = self.lower_block_expr(body);
406+ let expr_break = self.expr_break(span, ThinVec::new());
407+ let stmt_break = self.stmt_expr(span, expr_break);
408+ let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
409+ let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new()));
410+ let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
411+ let if_expr = self.expr(span, if_kind, ThinVec::new());
412+ let block = self.block_expr(self.arena.alloc(if_expr));
413+ hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span.with_hi(cond.span.hi()))
564414 }
565415
566416 /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -620,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
620470 fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
621471 let pat = self.lower_pat(&arm.pat);
622472 let guard = arm.guard.as_ref().map(|cond| {
623- if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind {
473+ if let ExprKind::Let(ref pat, ref scrutinee, _ ) = cond.kind {
624474 hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee))
625475 } else {
626476 hir::Guard::If(self.lower_expr(cond))
@@ -1468,7 +1318,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14681318 // `::std::option::Option::None => break`
14691319 let break_arm = {
14701320 let break_expr =
1471- self.with_loop_scope(e.id, |this| this.expr_break (e.span, ThinVec::new()));
1321+ self.with_loop_scope(e.id, |this| this.expr_break_alloc (e.span, ThinVec::new()));
14721322 let pat = self.pat_none(e.span);
14731323 self.arm(pat, break_expr)
14741324 };
@@ -1681,12 +1531,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
16811531 // Helper methods for building HIR.
16821532 // =========================================================================
16831533
1684- /// Constructs a `true` or `false` literal expression.
1685- pub(super) fn expr_bool(&mut self, span: Span, val: bool) -> &'hir hir::Expr<'hir> {
1686- let lit = Spanned { span, node: LitKind::Bool(val) };
1687- self.arena.alloc(self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new()))
1688- }
1689-
16901534 /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
16911535 ///
16921536 /// In terms of drop order, it has the same effect as wrapping `expr` in
@@ -1721,9 +1565,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
17211565 self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
17221566 }
17231567
1724- fn expr_break(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
1568+ fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
17251569 let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
1726- self.arena.alloc(self.expr(span, expr_break, attrs))
1570+ self.expr(span, expr_break, attrs)
1571+ }
1572+
1573+ fn expr_break_alloc(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
1574+ let expr_break = self.expr_break(span, attrs);
1575+ self.arena.alloc(expr_break)
17271576 }
17281577
17291578 fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
0 commit comments