@@ -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,188 +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 then = self . arena . alloc ( self . lower_block_expr ( then) ) ;
447- let els = else_opt. map ( |els| self . lower_expr ( els) ) ;
448- hir:: ExprKind :: If ( cond, then, els)
449- }
450-
451- fn lower_expr_if_let (
452- & mut self ,
453- span : Span ,
454- pat : & Pat ,
455- scrutinee : & Expr ,
456- then : & Block ,
457- else_opt : Option < & Expr > ,
458- ) -> hir:: ExprKind < ' hir > {
459- // FIXME(#53667): handle lowering of && and parens.
460-
461- // `_ => else_block` where `else_block` is `{}` if there's `None`:
462- let else_pat = self . pat_wild ( span) ;
463- let ( else_expr, contains_else_clause) = match else_opt {
464- None => ( self . expr_block_empty ( span. shrink_to_hi ( ) ) , false ) ,
465- Some ( els) => ( self . lower_expr ( els) , true ) ,
466- } ;
467- let else_arm = self . arm ( else_pat, else_expr) ;
468-
469- // Handle then + scrutinee:
470- let scrutinee = self . lower_expr ( scrutinee) ;
471- let then_pat = self . lower_pat ( pat) ;
472-
357+ let lowered_cond = self . lower_expr ( cond) ;
358+ let new_cond = self . manage_let_cond ( lowered_cond) ;
473359 let then_expr = self . lower_block_expr ( then) ;
474- let then_arm = self . arm ( then_pat, self . arena . alloc ( then_expr) ) ;
360+ if let Some ( rslt) = else_opt {
361+ hir:: ExprKind :: If ( new_cond, self . arena . alloc ( then_expr) , Some ( self . lower_expr ( rslt) ) )
362+ } else {
363+ hir:: ExprKind :: If ( new_cond, self . arena . alloc ( then_expr) , None )
364+ }
365+ }
475366
476- let desugar = hir:: MatchSource :: IfLetDesugar { contains_else_clause } ;
477- 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+ }
478378 }
479379
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`.
480396 fn lower_expr_while_in_loop_scope (
481397 & mut self ,
482398 span : Span ,
483399 cond : & Expr ,
484400 body : & Block ,
485401 opt_label : Option < Label > ,
486402 ) -> hir:: ExprKind < ' hir > {
487- // FIXME(#53667): handle lowering of && and parens.
488-
489- // Note that the block AND the condition are evaluated in the loop scope.
490- // This is done to allow `break` from inside the condition of the loop.
491-
492- // `_ => break`:
493- let else_arm = {
494- let else_pat = self . pat_wild ( span) ;
495- let else_expr = self . expr_break ( span, ThinVec :: new ( ) ) ;
496- self . arm ( else_pat, else_expr)
497- } ;
498-
499- // Handle then + scrutinee:
500- let ( then_pat, scrutinee, desugar, source) = match cond. kind {
501- ExprKind :: Let ( ref pat, ref scrutinee) => {
502- // to:
503- //
504- // [opt_ident]: loop {
505- // match <sub_expr> {
506- // <pat> => <body>,
507- // _ => break
508- // }
509- // }
510- let scrutinee = self . with_loop_condition_scope ( |t| t. lower_expr ( scrutinee) ) ;
511- let pat = self . lower_pat ( pat) ;
512- ( pat, scrutinee, hir:: MatchSource :: WhileLetDesugar , hir:: LoopSource :: WhileLet )
513- }
514- _ => {
515- // We desugar: `'label: while $cond $body` into:
516- //
517- // ```
518- // 'label: loop {
519- // match drop-temps { $cond } {
520- // true => $body,
521- // _ => break,
522- // }
523- // }
524- // ```
525-
526- // Lower condition:
527- let cond = self . with_loop_condition_scope ( |this| this. lower_expr ( cond) ) ;
528- let span_block =
529- self . mark_span_with_reason ( DesugaringKind :: CondTemporary , cond. span , None ) ;
530- // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
531- // to preserve drop semantics since `while cond { ... }` does not
532- // let temporaries live outside of `cond`.
533- let cond = self . expr_drop_temps ( span_block, cond, ThinVec :: new ( ) ) ;
534- // `true => <then>`:
535- let pat = self . pat_bool ( span, true ) ;
536- ( pat, cond, hir:: MatchSource :: WhileDesugar , hir:: LoopSource :: While )
537- }
538- } ;
539- let then_expr = self . lower_block_expr ( body) ;
540- let then_arm = self . arm ( then_pat, self . arena . alloc ( then_expr) ) ;
541-
542- // `match <scrutinee> { ... }`
543- let match_expr =
544- self . expr_match ( span, scrutinee, arena_vec ! [ self ; then_arm, else_arm] , desugar) ;
545-
546- // `[opt_ident]: loop { ... }`
547- hir:: ExprKind :: Loop (
548- self . block_expr ( self . arena . alloc ( match_expr) ) ,
549- opt_label,
550- source,
551- span. with_hi ( cond. span . hi ( ) ) ,
552- )
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 ( ) ) )
553414 }
554415
555416 /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -609,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
609470 fn lower_arm ( & mut self , arm : & Arm ) -> hir:: Arm < ' hir > {
610471 let pat = self . lower_pat ( & arm. pat ) ;
611472 let guard = arm. guard . as_ref ( ) . map ( |cond| {
612- if let ExprKind :: Let ( ref pat, ref scrutinee) = cond. kind {
473+ if let ExprKind :: Let ( ref pat, ref scrutinee, _ ) = cond. kind {
613474 hir:: Guard :: IfLet ( self . lower_pat ( pat) , self . lower_expr ( scrutinee) )
614475 } else {
615476 hir:: Guard :: If ( self . lower_expr ( cond) )
@@ -1457,7 +1318,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14571318 // `::std::option::Option::None => break`
14581319 let break_arm = {
14591320 let break_expr =
1460- 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 ( ) ) ) ;
14611322 let pat = self . pat_none ( e. span ) ;
14621323 self . arm ( pat, break_expr)
14631324 } ;
@@ -1670,12 +1531,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
16701531 // Helper methods for building HIR.
16711532 // =========================================================================
16721533
1673- /// Constructs a `true` or `false` literal expression.
1674- pub ( super ) fn expr_bool ( & mut self , span : Span , val : bool ) -> & ' hir hir:: Expr < ' hir > {
1675- let lit = Spanned { span, node : LitKind :: Bool ( val) } ;
1676- self . arena . alloc ( self . expr ( span, hir:: ExprKind :: Lit ( lit) , ThinVec :: new ( ) ) )
1677- }
1678-
16791534 /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
16801535 ///
16811536 /// In terms of drop order, it has the same effect as wrapping `expr` in
@@ -1710,9 +1565,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
17101565 self . expr ( span, hir:: ExprKind :: Match ( arg, arms, source) , ThinVec :: new ( ) )
17111566 }
17121567
1713- 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 > {
17141569 let expr_break = hir:: ExprKind :: Break ( self . lower_loop_destination ( None ) , None ) ;
1715- 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)
17161576 }
17171577
17181578 fn expr_mut_addr_of ( & mut self , span : Span , e : & ' hir hir:: Expr < ' hir > ) -> hir:: Expr < ' hir > {
0 commit comments