@@ -86,32 +86,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
86
86
let ohs = self . lower_expr ( ohs) ;
87
87
hir:: ExprKind :: AddrOf ( k, m, ohs)
88
88
}
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 ( ) )
91
94
}
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
- } ,
115
95
ExprKind :: While ( ref cond, ref body, opt_label) => self
116
96
. with_loop_scope ( e. id , |this| {
117
97
this. lower_expr_while_in_loop_scope ( e. span , cond, body, opt_label)
@@ -368,188 +348,69 @@ impl<'hir> LoweringContext<'_, 'hir> {
368
348
hir:: ExprKind :: Call ( f, self . lower_exprs ( & real_args) )
369
349
}
370
350
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
-
439
351
fn lower_expr_if (
440
352
& mut self ,
441
353
cond : & Expr ,
442
354
then : & Block ,
443
355
else_opt : Option < & Expr > ,
444
356
) -> 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) ;
473
359
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
+ }
475
366
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
+ }
478
378
}
479
379
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`.
480
396
fn lower_expr_while_in_loop_scope (
481
397
& mut self ,
482
398
span : Span ,
483
399
cond : & Expr ,
484
400
body : & Block ,
485
401
opt_label : Option < Label > ,
486
402
) -> 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 ( ) ) )
553
414
}
554
415
555
416
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -609,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
609
470
fn lower_arm ( & mut self , arm : & Arm ) -> hir:: Arm < ' hir > {
610
471
let pat = self . lower_pat ( & arm. pat ) ;
611
472
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 {
613
474
hir:: Guard :: IfLet ( self . lower_pat ( pat) , self . lower_expr ( scrutinee) )
614
475
} else {
615
476
hir:: Guard :: If ( self . lower_expr ( cond) )
@@ -1457,7 +1318,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
1457
1318
// `::std::option::Option::None => break`
1458
1319
let break_arm = {
1459
1320
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 ( ) ) ) ;
1461
1322
let pat = self . pat_none ( e. span ) ;
1462
1323
self . arm ( pat, break_expr)
1463
1324
} ;
@@ -1670,12 +1531,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
1670
1531
// Helper methods for building HIR.
1671
1532
// =========================================================================
1672
1533
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
-
1679
1534
/// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
1680
1535
///
1681
1536
/// In terms of drop order, it has the same effect as wrapping `expr` in
@@ -1710,9 +1565,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
1710
1565
self . expr ( span, hir:: ExprKind :: Match ( arg, arms, source) , ThinVec :: new ( ) )
1711
1566
}
1712
1567
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 > {
1714
1569
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)
1716
1576
}
1717
1577
1718
1578
fn expr_mut_addr_of ( & mut self , span : Span , e : & ' hir hir:: Expr < ' hir > ) -> hir:: Expr < ' hir > {
0 commit comments