@@ -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