@@ -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,199 +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 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) ;
450
359
let then_expr = self . lower_block_expr ( then) ;
451
360
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) ) )
457
362
} 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 )
459
364
}
460
365
}
461
366
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
+ }
489
378
}
490
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`.
491
396
fn lower_expr_while_in_loop_scope (
492
397
& mut self ,
493
398
span : Span ,
494
399
cond : & Expr ,
495
400
body : & Block ,
496
401
opt_label : Option < Label > ,
497
402
) -> 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 ( ) ) )
564
414
}
565
415
566
416
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -620,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
620
470
fn lower_arm ( & mut self , arm : & Arm ) -> hir:: Arm < ' hir > {
621
471
let pat = self . lower_pat ( & arm. pat ) ;
622
472
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 {
624
474
hir:: Guard :: IfLet ( self . lower_pat ( pat) , self . lower_expr ( scrutinee) )
625
475
} else {
626
476
hir:: Guard :: If ( self . lower_expr ( cond) )
@@ -1468,7 +1318,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
1468
1318
// `::std::option::Option::None => break`
1469
1319
let break_arm = {
1470
1320
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 ( ) ) ) ;
1472
1322
let pat = self . pat_none ( e. span ) ;
1473
1323
self . arm ( pat, break_expr)
1474
1324
} ;
@@ -1681,12 +1531,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
1681
1531
// Helper methods for building HIR.
1682
1532
// =========================================================================
1683
1533
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
-
1690
1534
/// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
1691
1535
///
1692
1536
/// In terms of drop order, it has the same effect as wrapping `expr` in
@@ -1721,9 +1565,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
1721
1565
self . expr ( span, hir:: ExprKind :: Match ( arg, arms, source) , ThinVec :: new ( ) )
1722
1566
}
1723
1567
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 > {
1725
1569
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)
1727
1576
}
1728
1577
1729
1578
fn expr_mut_addr_of ( & mut self , span : Span , e : & ' hir hir:: Expr < ' hir > ) -> hir:: Expr < ' hir > {
0 commit comments