@@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
8585 hir:: ExprKind :: AddrOf ( k, m, ohs)
8686 }
8787 ExprKind :: Let ( ref pat, ref scrutinee) => {
88- self . lower_expr_let ( e . span , pat, scrutinee)
88+ hir :: ExprKind :: Let ( self . lower_pat ( pat) , self . lower_expr ( scrutinee) )
8989 }
9090 ExprKind :: If ( ref cond, ref then, ref else_opt) => {
9191 self . lower_expr_if ( e. span , cond, then, else_opt. as_deref ( ) )
@@ -268,51 +268,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
268268 }
269269 }
270270
271- /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into:
272- /// ```rust
273- /// match scrutinee { pats => true, _ => false }
274- /// ```
275- fn lower_expr_let ( & mut self , span : Span , pat : & Pat , scrutinee : & Expr ) -> hir:: ExprKind < ' hir > {
276- // If we got here, the `let` expression is not allowed.
277-
278- if self . sess . opts . unstable_features . is_nightly_build ( ) {
279- self . sess
280- . struct_span_err ( span, "`let` expressions are not supported here" )
281- . note ( "only supported directly in conditions of `if`- and `while`-expressions" )
282- . note ( "as well as when nested within `&&` and parenthesis in those conditions" )
283- . emit ( ) ;
284- } else {
285- self . sess
286- . struct_span_err ( span, "expected expression, found statement (`let`)" )
287- . note ( "variable declaration using `let` is a statement" )
288- . emit ( ) ;
271+ /// Lower the condition of an `if` or `while` expression.
272+ /// This entails some special handling of immediate `let` expressions as conditions.
273+ /// Namely, if the given `cond` is not a `let` expression then it is wrapped in `drop-temps`.
274+ fn lower_expr_cond ( & mut self , cond : & Expr ) -> & ' hir hir:: Expr < ' hir > {
275+ // Lower the `cond` expression.
276+ let cond = self . lower_expr ( cond) ;
277+ // Normally, the `cond` of `if cond` will drop temporaries before evaluating the blocks.
278+ // This is achieved by using `drop-temps { cond }`, equivalent to `{ let _t = $cond; _t }`.
279+ // However, for backwards compatibility reasons, `if let pat = scrutinee`, like `match`
280+ // does not drop the temporaries of `scrutinee` before evaluating the blocks.
281+ match cond. kind {
282+ hir:: ExprKind :: Let ( ..) => cond,
283+ _ => {
284+ let reason = DesugaringKind :: CondTemporary ;
285+ let span = self . mark_span_with_reason ( reason, cond. span , None ) ;
286+ self . expr_drop_temps ( span, cond, ThinVec :: new ( ) )
287+ }
289288 }
289+ }
290290
291- // For better recovery, we emit:
292- // ```
293- // match scrutinee { pat => true, _ => false }
294- // ```
295- // While this doesn't fully match the user's intent, it has key advantages:
296- // 1. We can avoid using `abort_if_errors`.
297- // 2. We can typeck both `pat` and `scrutinee`.
298- // 3. `pat` is allowed to be refutable.
299- // 4. The return type of the block is `bool` which seems like what the user wanted.
300- let scrutinee = self . lower_expr ( scrutinee) ;
301- let then_arm = {
302- let pat = self . lower_pat ( pat) ;
303- let expr = self . expr_bool ( span, true ) ;
304- self . arm ( pat, expr)
305- } ;
306- let else_arm = {
307- let pat = self . pat_wild ( span) ;
308- let expr = self . expr_bool ( span, false ) ;
309- self . arm ( pat, expr)
310- } ;
311- hir:: ExprKind :: Match (
312- scrutinee,
313- arena_vec ! [ self ; then_arm, else_arm] ,
314- hir:: MatchSource :: Normal ,
315- )
291+ /// Lower `then` into `true => then`.
292+ fn lower_then_arm ( & mut self , span : Span , then : & Block ) -> hir:: Arm < ' hir > {
293+ let then_expr = self . lower_block_expr ( then) ;
294+ let then_pat = self . pat_bool ( span, true ) ;
295+ self . arm ( then_pat, self . arena . alloc ( then_expr) )
296+ }
297+
298+ fn lower_else_arm ( & mut self , span : Span , else_expr : & ' hir hir:: Expr < ' hir > ) -> hir:: Arm < ' hir > {
299+ let else_pat = self . pat_wild ( span) ;
300+ self . arm ( else_pat, else_expr)
316301 }
317302
318303 fn lower_expr_if (
@@ -322,112 +307,53 @@ impl<'hir> LoweringContext<'_, 'hir> {
322307 then : & Block ,
323308 else_opt : Option < & Expr > ,
324309 ) -> hir:: ExprKind < ' hir > {
325- // FIXME(#53667): handle lowering of && and parens.
326-
327- // `_ => else_block` where `else_block` is `{}` if there's `None`:
328- let else_pat = self . pat_wild ( span) ;
329- let ( else_expr, contains_else_clause) = match else_opt {
330- None => ( self . expr_block_empty ( span) , false ) ,
331- Some ( els) => ( self . lower_expr ( els) , true ) ,
310+ let scrutinee = self . lower_expr_cond ( cond) ;
311+ let then_arm = self . lower_then_arm ( span, then) ;
312+ let else_expr = match else_opt {
313+ None => self . expr_block_empty ( span) , // Use `{}` if there's no `else` block.
314+ Some ( els) => self . lower_expr ( els) ,
332315 } ;
333- let else_arm = self . arm ( else_pat, else_expr) ;
334-
335- // Handle then + scrutinee:
336- let then_expr = self . lower_block_expr ( then) ;
337- let ( then_pat, scrutinee, desugar) = match cond. kind {
338- // `<pat> => <then>`:
339- ExprKind :: Let ( ref pat, ref scrutinee) => {
340- let scrutinee = self . lower_expr ( scrutinee) ;
341- let pat = self . lower_pat ( pat) ;
342- ( pat, scrutinee, hir:: MatchSource :: IfLetDesugar { contains_else_clause } )
343- }
344- // `true => <then>`:
345- _ => {
346- // Lower condition:
347- let cond = self . lower_expr ( cond) ;
348- let span_block =
349- self . mark_span_with_reason ( DesugaringKind :: CondTemporary , cond. span , None ) ;
350- // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
351- // to preserve drop semantics since `if cond { ... }` does not
352- // let temporaries live outside of `cond`.
353- let cond = self . expr_drop_temps ( span_block, cond, ThinVec :: new ( ) ) ;
354- let pat = self . pat_bool ( span, true ) ;
355- ( pat, cond, hir:: MatchSource :: IfDesugar { contains_else_clause } )
356- }
357- } ;
358- let then_arm = self . arm ( then_pat, self . arena . alloc ( then_expr) ) ;
359-
316+ let else_arm = self . lower_else_arm ( span, else_expr) ;
317+ let desugar = hir:: MatchSource :: IfDesugar { contains_else_clause : else_opt. is_some ( ) } ;
360318 hir:: ExprKind :: Match ( scrutinee, arena_vec ! [ self ; then_arm, else_arm] , desugar)
361319 }
362320
321+ /// We desugar: `'label: while $cond $body` into:
322+ ///
323+ /// ```
324+ /// 'label: loop {
325+ /// match $cond {
326+ /// true => $body,
327+ /// _ => break,
328+ /// }
329+ /// }
330+ /// ```
331+ ///
332+ /// where `$cond` is wrapped in `drop-temps { $cond }` if it isn't a `Let` expression.
363333 fn lower_expr_while_in_loop_scope (
364334 & mut self ,
365335 span : Span ,
366336 cond : & Expr ,
367337 body : & Block ,
368338 opt_label : Option < Label > ,
369339 ) -> hir:: ExprKind < ' hir > {
370- // FIXME(#53667): handle lowering of && and parens.
371-
372340 // Note that the block AND the condition are evaluated in the loop scope.
373341 // This is done to allow `break` from inside the condition of the loop.
374342
343+ // Lower the condition:
344+ let scrutinee = self . with_loop_condition_scope ( |t| t. lower_expr_cond ( cond) ) ;
345+ // `true => body`:
346+ let then_arm = self . lower_then_arm ( span, body) ;
375347 // `_ => break`:
376- let else_arm = {
377- let else_pat = self . pat_wild ( span) ;
378- let else_expr = self . expr_break ( span, ThinVec :: new ( ) ) ;
379- self . arm ( else_pat, else_expr)
380- } ;
381-
382- // Handle then + scrutinee:
383- let then_expr = self . lower_block_expr ( body) ;
384- let ( then_pat, scrutinee, desugar, source) = match cond. kind {
385- ExprKind :: Let ( ref pat, ref scrutinee) => {
386- // to:
387- //
388- // [opt_ident]: loop {
389- // match <sub_expr> {
390- // <pat> => <body>,
391- // _ => break
392- // }
393- // }
394- let scrutinee = self . with_loop_condition_scope ( |t| t. lower_expr ( scrutinee) ) ;
395- let pat = self . lower_pat ( pat) ;
396- ( pat, scrutinee, hir:: MatchSource :: WhileLetDesugar , hir:: LoopSource :: WhileLet )
397- }
398- _ => {
399- // We desugar: `'label: while $cond $body` into:
400- //
401- // ```
402- // 'label: loop {
403- // match drop-temps { $cond } {
404- // true => $body,
405- // _ => break,
406- // }
407- // }
408- // ```
409-
410- // Lower condition:
411- let cond = self . with_loop_condition_scope ( |this| this. lower_expr ( cond) ) ;
412- let span_block =
413- self . mark_span_with_reason ( DesugaringKind :: CondTemporary , cond. span , None ) ;
414- // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
415- // to preserve drop semantics since `while cond { ... }` does not
416- // let temporaries live outside of `cond`.
417- let cond = self . expr_drop_temps ( span_block, cond, ThinVec :: new ( ) ) ;
418- // `true => <then>`:
419- let pat = self . pat_bool ( span, true ) ;
420- ( pat, cond, hir:: MatchSource :: WhileDesugar , hir:: LoopSource :: While )
421- }
422- } ;
423- let then_arm = self . arm ( then_pat, self . arena . alloc ( then_expr) ) ;
424-
348+ let else_expr = self . expr_break ( span, ThinVec :: new ( ) ) ;
349+ let else_arm = self . lower_else_arm ( span, else_expr) ;
425350 // `match <scrutinee> { ... }`
426- let match_expr =
427- self . expr_match ( span , scrutinee , arena_vec ! [ self ; then_arm , else_arm ] , desugar ) ;
428-
351+ let match_arms = arena_vec ! [ self ; then_arm , else_arm ] ;
352+ let match_desugar = hir :: MatchSource :: WhileDesugar ;
353+ let match_expr = self . expr_match ( span , scrutinee , match_arms , match_desugar ) ;
429354 // `[opt_ident]: loop { ... }`
430- hir:: ExprKind :: Loop ( self . block_expr ( self . arena . alloc ( match_expr) ) , opt_label, source)
355+ let loop_block = self . block_expr ( self . arena . alloc ( match_expr) ) ;
356+ hir:: ExprKind :: Loop ( loop_block, opt_label, hir:: LoopSource :: While )
431357 }
432358
433359 /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
0 commit comments