@@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
85
85
hir:: ExprKind :: AddrOf ( k, m, ohs)
86
86
}
87
87
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) )
89
89
}
90
90
ExprKind :: If ( ref cond, ref then, ref else_opt) => {
91
91
self . lower_expr_if ( e. span , cond, then, else_opt. as_deref ( ) )
@@ -268,51 +268,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
268
268
}
269
269
}
270
270
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
+ }
289
288
}
289
+ }
290
290
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)
316
301
}
317
302
318
303
fn lower_expr_if (
@@ -322,112 +307,53 @@ impl<'hir> LoweringContext<'_, 'hir> {
322
307
then : & Block ,
323
308
else_opt : Option < & Expr > ,
324
309
) -> 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) ,
332
315
} ;
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 ( ) } ;
360
318
hir:: ExprKind :: Match ( scrutinee, arena_vec ! [ self ; then_arm, else_arm] , desugar)
361
319
}
362
320
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.
363
333
fn lower_expr_while_in_loop_scope (
364
334
& mut self ,
365
335
span : Span ,
366
336
cond : & Expr ,
367
337
body : & Block ,
368
338
opt_label : Option < Label > ,
369
339
) -> hir:: ExprKind < ' hir > {
370
- // FIXME(#53667): handle lowering of && and parens.
371
-
372
340
// Note that the block AND the condition are evaluated in the loop scope.
373
341
// This is done to allow `break` from inside the condition of the loop.
374
342
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) ;
375
347
// `_ => 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) ;
425
350
// `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 ) ;
429
354
// `[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 )
431
357
}
432
358
433
359
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
0 commit comments