@@ -4344,53 +4344,120 @@ impl<'a> LoweringContext<'a> {
4344
4344
let ohs = P ( self . lower_expr ( ohs) ) ;
4345
4345
hir:: ExprKind :: AddrOf ( m, ohs)
4346
4346
}
4347
- // More complicated than you might expect because the else branch
4348
- // might be `if let`.
4347
+ ExprKind :: Let ( ..) => {
4348
+ // This should have been caught `ast_validation`!
4349
+ self . sess . span_err ( e. span , "`let` expressions only supported in `if`" ) ;
4350
+ // ^-- FIXME(53667): Change to `delay_span_bug` when let_chains handled in lowering.
4351
+ self . sess . abort_if_errors ( ) ;
4352
+ hir:: ExprKind :: Err
4353
+ }
4354
+ // FIXME(#53667): handle lowering of && and parens.
4349
4355
ExprKind :: If ( ref cond, ref then, ref else_opt) => {
4350
- // `true => then`:
4351
- let then_pat = self . pat_bool ( e. span , true ) ;
4352
- let then_blk = self . lower_block ( then, false ) ;
4353
- let then_expr = self . expr_block ( then_blk, ThinVec :: new ( ) ) ;
4354
- let then_arm = self . arm ( hir_vec ! [ then_pat] , P ( then_expr) ) ;
4355
-
4356
4356
// `_ => else_block` where `else_block` is `{}` if there's `None`:
4357
4357
let else_pat = self . pat_wild ( e. span ) ;
4358
- let else_expr = match else_opt {
4359
- None => self . expr_block_empty ( e. span ) ,
4360
- Some ( els) => match els. node {
4361
- ExprKind :: IfLet ( ..) => {
4362
- // Wrap the `if let` expr in a block.
4363
- let els = self . lower_expr ( els) ;
4364
- let blk = self . block_all ( els. span , hir_vec ! [ ] , Some ( P ( els) ) ) ;
4365
- self . expr_block ( P ( blk) , ThinVec :: new ( ) )
4366
- }
4367
- _ => self . lower_expr ( els) ,
4368
- }
4358
+ let ( else_expr, contains_else_clause) = match else_opt {
4359
+ None => ( self . expr_block_empty ( e. span ) , false ) ,
4360
+ Some ( els) => ( self . lower_expr ( els) , true ) ,
4369
4361
} ;
4370
4362
let else_arm = self . arm ( hir_vec ! [ else_pat] , P ( else_expr) ) ;
4371
4363
4372
- // Lower condition:
4373
- let span_block = self . mark_span_with_reason ( IfTemporary , cond. span , None ) ;
4374
- let cond = self . lower_expr ( cond) ;
4375
- // Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
4376
- // semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
4377
- let cond = self . expr_drop_temps ( span_block, P ( cond) , ThinVec :: new ( ) ) ;
4364
+ // Handle then + scrutinee:
4365
+ let then_blk = self . lower_block ( then, false ) ;
4366
+ let then_expr = self . expr_block ( then_blk, ThinVec :: new ( ) ) ;
4367
+ let ( then_pats, scrutinee, desugar) = match cond. node {
4368
+ // `<pat> => <then>`
4369
+ ExprKind :: Let ( ref pats, ref scrutinee) => {
4370
+ let scrutinee = self . lower_expr ( scrutinee) ;
4371
+ let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4372
+ let desugar = hir:: MatchSource :: IfLetDesugar { contains_else_clause } ;
4373
+ ( pats, scrutinee, desugar)
4374
+ }
4375
+ // `true => then`:
4376
+ _ => {
4377
+ // Lower condition:
4378
+ let cond = self . lower_expr ( cond) ;
4379
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4380
+ // to preserve drop semantics since `if cond { ... }`
4381
+ // don't let temporaries live outside of `cond`.
4382
+ let span_block = self . mark_span_with_reason ( IfTemporary , cond. span , None ) ;
4383
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4384
+ // to preserve drop semantics since `if cond { ... }` does not
4385
+ // let temporaries live outside of `cond`.
4386
+ let cond = self . expr_drop_temps ( span_block, P ( cond) , ThinVec :: new ( ) ) ;
4387
+
4388
+ let desugar = hir:: MatchSource :: IfDesugar { contains_else_clause } ;
4389
+ let pats = hir_vec ! [ self . pat_bool( e. span, true ) ] ;
4390
+ ( pats, cond, desugar)
4391
+ }
4392
+ } ;
4393
+ let then_arm = self . arm ( then_pats, P ( then_expr) ) ;
4378
4394
4379
- hir:: ExprKind :: Match (
4380
- P ( cond) ,
4381
- vec ! [ then_arm, else_arm] . into ( ) ,
4382
- hir:: MatchSource :: IfDesugar {
4383
- contains_else_clause : else_opt. is_some ( )
4384
- } ,
4385
- )
4395
+ hir:: ExprKind :: Match ( P ( scrutinee) , vec ! [ then_arm, else_arm] . into ( ) , desugar)
4396
+ }
4397
+ // FIXME(#53667): handle lowering of && and parens.
4398
+ ExprKind :: While ( ref cond, ref body, opt_label) => {
4399
+ // Desugar `ExprWhileLet`
4400
+ // from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
4401
+ if let ExprKind :: Let ( ref pats, ref sub_expr) = cond. node {
4402
+ // to:
4403
+ //
4404
+ // [opt_ident]: loop {
4405
+ // match <sub_expr> {
4406
+ // <pat> => <body>,
4407
+ // _ => break
4408
+ // }
4409
+ // }
4410
+
4411
+ // Note that the block AND the condition are evaluated in the loop scope.
4412
+ // This is done to allow `break` from inside the condition of the loop.
4413
+ let ( body, break_expr, sub_expr) = self . with_loop_scope ( e. id , |this| {
4414
+ (
4415
+ this. lower_block ( body, false ) ,
4416
+ this. expr_break ( e. span , ThinVec :: new ( ) ) ,
4417
+ this. with_loop_condition_scope ( |this| P ( this. lower_expr ( sub_expr) ) ) ,
4418
+ )
4419
+ } ) ;
4420
+
4421
+ // `<pat> => <body>`
4422
+ let pat_arm = {
4423
+ let body_expr = P ( self . expr_block ( body, ThinVec :: new ( ) ) ) ;
4424
+ let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4425
+ self . arm ( pats, body_expr)
4426
+ } ;
4427
+
4428
+ // `_ => break`
4429
+ let break_arm = {
4430
+ let pat_under = self . pat_wild ( e. span ) ;
4431
+ self . arm ( hir_vec ! [ pat_under] , break_expr)
4432
+ } ;
4433
+
4434
+ // `match <sub_expr> { ... }`
4435
+ let arms = hir_vec ! [ pat_arm, break_arm] ;
4436
+ let match_expr = self . expr (
4437
+ sub_expr. span ,
4438
+ hir:: ExprKind :: Match ( sub_expr, arms, hir:: MatchSource :: WhileLetDesugar ) ,
4439
+ ThinVec :: new ( ) ,
4440
+ ) ;
4441
+
4442
+ // `[opt_ident]: loop { ... }`
4443
+ let loop_block = P ( self . block_expr ( P ( match_expr) ) ) ;
4444
+ let loop_expr = hir:: ExprKind :: Loop (
4445
+ loop_block,
4446
+ self . lower_label ( opt_label) ,
4447
+ hir:: LoopSource :: WhileLet ,
4448
+ ) ;
4449
+ // Add attributes to the outer returned expr node.
4450
+ loop_expr
4451
+ } else {
4452
+ self . with_loop_scope ( e. id , |this| {
4453
+ hir:: ExprKind :: While (
4454
+ this. with_loop_condition_scope ( |this| P ( this. lower_expr ( cond) ) ) ,
4455
+ this. lower_block ( body, false ) ,
4456
+ this. lower_label ( opt_label) ,
4457
+ )
4458
+ } )
4459
+ }
4386
4460
}
4387
- ExprKind :: While ( ref cond, ref body, opt_label) => self . with_loop_scope ( e. id , |this| {
4388
- hir:: ExprKind :: While (
4389
- this. with_loop_condition_scope ( |this| P ( this. lower_expr ( cond) ) ) ,
4390
- this. lower_block ( body, false ) ,
4391
- this. lower_label ( opt_label) ,
4392
- )
4393
- } ) ,
4394
4461
ExprKind :: Loop ( ref body, opt_label) => self . with_loop_scope ( e. id , |this| {
4395
4462
hir:: ExprKind :: Loop (
4396
4463
this. lower_block ( body, false ) ,
@@ -4703,105 +4770,6 @@ impl<'a> LoweringContext<'a> {
4703
4770
4704
4771
ExprKind :: Err => hir:: ExprKind :: Err ,
4705
4772
4706
- // Desugar `ExprIfLet`
4707
- // from: `if let <pat> = <sub_expr> <body> [<else_opt>]`
4708
- ExprKind :: IfLet ( ref pats, ref sub_expr, ref body, ref else_opt) => {
4709
- // to:
4710
- //
4711
- // match <sub_expr> {
4712
- // <pat> => <body>,
4713
- // _ => [<else_opt> | ()]
4714
- // }
4715
-
4716
- let mut arms = vec ! [ ] ;
4717
-
4718
- // `<pat> => <body>`
4719
- {
4720
- let body = self . lower_block ( body, false ) ;
4721
- let body_expr = P ( self . expr_block ( body, ThinVec :: new ( ) ) ) ;
4722
- let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4723
- arms. push ( self . arm ( pats, body_expr) ) ;
4724
- }
4725
-
4726
- // _ => [<else_opt>|{}]
4727
- {
4728
- let wildcard_arm: Option < & Expr > = else_opt. as_ref ( ) . map ( |p| & * * p) ;
4729
- let wildcard_pattern = self . pat_wild ( e. span ) ;
4730
- let body = if let Some ( else_expr) = wildcard_arm {
4731
- self . lower_expr ( else_expr)
4732
- } else {
4733
- self . expr_block_empty ( e. span )
4734
- } ;
4735
- arms. push ( self . arm ( hir_vec ! [ wildcard_pattern] , P ( body) ) ) ;
4736
- }
4737
-
4738
- let contains_else_clause = else_opt. is_some ( ) ;
4739
-
4740
- let sub_expr = P ( self . lower_expr ( sub_expr) ) ;
4741
-
4742
- hir:: ExprKind :: Match (
4743
- sub_expr,
4744
- arms. into ( ) ,
4745
- hir:: MatchSource :: IfLetDesugar {
4746
- contains_else_clause,
4747
- } ,
4748
- )
4749
- }
4750
-
4751
- // Desugar `ExprWhileLet`
4752
- // from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
4753
- ExprKind :: WhileLet ( ref pats, ref sub_expr, ref body, opt_label) => {
4754
- // to:
4755
- //
4756
- // [opt_ident]: loop {
4757
- // match <sub_expr> {
4758
- // <pat> => <body>,
4759
- // _ => break
4760
- // }
4761
- // }
4762
-
4763
- // Note that the block AND the condition are evaluated in the loop scope.
4764
- // This is done to allow `break` from inside the condition of the loop.
4765
- let ( body, break_expr, sub_expr) = self . with_loop_scope ( e. id , |this| {
4766
- (
4767
- this. lower_block ( body, false ) ,
4768
- this. expr_break ( e. span , ThinVec :: new ( ) ) ,
4769
- this. with_loop_condition_scope ( |this| P ( this. lower_expr ( sub_expr) ) ) ,
4770
- )
4771
- } ) ;
4772
-
4773
- // `<pat> => <body>`
4774
- let pat_arm = {
4775
- let body_expr = P ( self . expr_block ( body, ThinVec :: new ( ) ) ) ;
4776
- let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4777
- self . arm ( pats, body_expr)
4778
- } ;
4779
-
4780
- // `_ => break`
4781
- let break_arm = {
4782
- let pat_under = self . pat_wild ( e. span ) ;
4783
- self . arm ( hir_vec ! [ pat_under] , break_expr)
4784
- } ;
4785
-
4786
- // `match <sub_expr> { ... }`
4787
- let arms = hir_vec ! [ pat_arm, break_arm] ;
4788
- let match_expr = self . expr (
4789
- sub_expr. span ,
4790
- hir:: ExprKind :: Match ( sub_expr, arms, hir:: MatchSource :: WhileLetDesugar ) ,
4791
- ThinVec :: new ( ) ,
4792
- ) ;
4793
-
4794
- // `[opt_ident]: loop { ... }`
4795
- let loop_block = P ( self . block_expr ( P ( match_expr) ) ) ;
4796
- let loop_expr = hir:: ExprKind :: Loop (
4797
- loop_block,
4798
- self . lower_label ( opt_label) ,
4799
- hir:: LoopSource :: WhileLet ,
4800
- ) ;
4801
- // Add attributes to the outer returned expr node.
4802
- loop_expr
4803
- }
4804
-
4805
4773
// Desugar `ExprForLoop`
4806
4774
// from: `[opt_ident]: for <pat> in <head> <body>`
4807
4775
ExprKind :: ForLoop ( ref pat, ref head, ref body, opt_label) => {
0 commit comments