@@ -4344,53 +4344,147 @@ 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 ( ref pats, ref scrutinee) => {
4348
+ // If we got here, the `let` expression is not allowed.
4349
+ self . sess
4350
+ . struct_span_err ( e. span , "`let` expressions are not supported here" )
4351
+ . note ( "only supported directly in conditions of `if`- and `while`-expressions" )
4352
+ . note ( "as well as when nested within `&&` and parenthesis in those conditions" )
4353
+ . emit ( ) ;
4354
+
4355
+ // For better recovery, we emit:
4356
+ // ```
4357
+ // match scrutinee { pats => true, _ => false }
4358
+ // ```
4359
+ // While this doesn't fully match the user's intent, it has key advantages:
4360
+ // 1. We can avoid using `abort_if_errors`.
4361
+ // 2. We can typeck both `pats` and `scrutinee`.
4362
+ // 3. `pats` is allowed to be refutable.
4363
+ // 4. The return type of the block is `bool` which seems like what the user wanted.
4364
+ let scrutinee = self . lower_expr ( scrutinee) ;
4365
+ let then_arm = {
4366
+ let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4367
+ let expr = self . expr_bool ( e. span , true ) ;
4368
+ self . arm ( pats, P ( expr) )
4369
+ } ;
4370
+ let else_arm = {
4371
+ let pats = hir_vec ! [ self . pat_wild( e. span) ] ;
4372
+ let expr = self . expr_bool ( e. span , false ) ;
4373
+ self . arm ( pats, P ( expr) )
4374
+ } ;
4375
+ hir:: ExprKind :: Match (
4376
+ P ( scrutinee) ,
4377
+ vec ! [ then_arm, else_arm] . into ( ) ,
4378
+ hir:: MatchSource :: Normal ,
4379
+ )
4380
+ }
4381
+ // FIXME(#53667): handle lowering of && and parens.
4349
4382
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
4383
// `_ => else_block` where `else_block` is `{}` if there's `None`:
4357
4384
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
- }
4385
+ let ( else_expr, contains_else_clause) = match else_opt {
4386
+ None => ( self . expr_block_empty ( e. span ) , false ) ,
4387
+ Some ( els) => ( self . lower_expr ( els) , true ) ,
4369
4388
} ;
4370
4389
let else_arm = self . arm ( hir_vec ! [ else_pat] , P ( else_expr) ) ;
4371
4390
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 ( ) ) ;
4391
+ // Handle then + scrutinee:
4392
+ let then_blk = self . lower_block ( then, false ) ;
4393
+ let then_expr = self . expr_block ( then_blk, ThinVec :: new ( ) ) ;
4394
+ let ( then_pats, scrutinee, desugar) = match cond. node {
4395
+ // `<pat> => <then>`
4396
+ ExprKind :: Let ( ref pats, ref scrutinee) => {
4397
+ let scrutinee = self . lower_expr ( scrutinee) ;
4398
+ let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4399
+ let desugar = hir:: MatchSource :: IfLetDesugar { contains_else_clause } ;
4400
+ ( pats, scrutinee, desugar)
4401
+ }
4402
+ // `true => then`:
4403
+ _ => {
4404
+ // Lower condition:
4405
+ let cond = self . lower_expr ( cond) ;
4406
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4407
+ // to preserve drop semantics since `if cond { ... }`
4408
+ // don't let temporaries live outside of `cond`.
4409
+ let span_block = self . mark_span_with_reason ( IfTemporary , cond. span , None ) ;
4410
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4411
+ // to preserve drop semantics since `if cond { ... }` does not
4412
+ // let temporaries live outside of `cond`.
4413
+ let cond = self . expr_drop_temps ( span_block, P ( cond) , ThinVec :: new ( ) ) ;
4414
+
4415
+ let desugar = hir:: MatchSource :: IfDesugar { contains_else_clause } ;
4416
+ let pats = hir_vec ! [ self . pat_bool( e. span, true ) ] ;
4417
+ ( pats, cond, desugar)
4418
+ }
4419
+ } ;
4420
+ let then_arm = self . arm ( then_pats, P ( then_expr) ) ;
4378
4421
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
- )
4422
+ hir:: ExprKind :: Match ( P ( scrutinee) , vec ! [ then_arm, else_arm] . into ( ) , desugar)
4423
+ }
4424
+ // FIXME(#53667): handle lowering of && and parens.
4425
+ ExprKind :: While ( ref cond, ref body, opt_label) => {
4426
+ // Desugar `ExprWhileLet`
4427
+ // from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
4428
+ if let ExprKind :: Let ( ref pats, ref sub_expr) = cond. node {
4429
+ // to:
4430
+ //
4431
+ // [opt_ident]: loop {
4432
+ // match <sub_expr> {
4433
+ // <pat> => <body>,
4434
+ // _ => break
4435
+ // }
4436
+ // }
4437
+
4438
+ // Note that the block AND the condition are evaluated in the loop scope.
4439
+ // This is done to allow `break` from inside the condition of the loop.
4440
+ let ( body, break_expr, sub_expr) = self . with_loop_scope ( e. id , |this| {
4441
+ (
4442
+ this. lower_block ( body, false ) ,
4443
+ this. expr_break ( e. span , ThinVec :: new ( ) ) ,
4444
+ this. with_loop_condition_scope ( |this| P ( this. lower_expr ( sub_expr) ) ) ,
4445
+ )
4446
+ } ) ;
4447
+
4448
+ // `<pat> => <body>`
4449
+ let pat_arm = {
4450
+ let body_expr = P ( self . expr_block ( body, ThinVec :: new ( ) ) ) ;
4451
+ let pats = pats. iter ( ) . map ( |pat| self . lower_pat ( pat) ) . collect ( ) ;
4452
+ self . arm ( pats, body_expr)
4453
+ } ;
4454
+
4455
+ // `_ => break`
4456
+ let break_arm = {
4457
+ let pat_under = self . pat_wild ( e. span ) ;
4458
+ self . arm ( hir_vec ! [ pat_under] , break_expr)
4459
+ } ;
4460
+
4461
+ // `match <sub_expr> { ... }`
4462
+ let arms = hir_vec ! [ pat_arm, break_arm] ;
4463
+ let match_expr = self . expr (
4464
+ sub_expr. span ,
4465
+ hir:: ExprKind :: Match ( sub_expr, arms, hir:: MatchSource :: WhileLetDesugar ) ,
4466
+ ThinVec :: new ( ) ,
4467
+ ) ;
4468
+
4469
+ // `[opt_ident]: loop { ... }`
4470
+ let loop_block = P ( self . block_expr ( P ( match_expr) ) ) ;
4471
+ let loop_expr = hir:: ExprKind :: Loop (
4472
+ loop_block,
4473
+ self . lower_label ( opt_label) ,
4474
+ hir:: LoopSource :: WhileLet ,
4475
+ ) ;
4476
+ // Add attributes to the outer returned expr node.
4477
+ loop_expr
4478
+ } else {
4479
+ self . with_loop_scope ( e. id , |this| {
4480
+ hir:: ExprKind :: While (
4481
+ this. with_loop_condition_scope ( |this| P ( this. lower_expr ( cond) ) ) ,
4482
+ this. lower_block ( body, false ) ,
4483
+ this. lower_label ( opt_label) ,
4484
+ )
4485
+ } )
4486
+ }
4386
4487
}
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
4488
ExprKind :: Loop ( ref body, opt_label) => self . with_loop_scope ( e. id , |this| {
4395
4489
hir:: ExprKind :: Loop (
4396
4490
this. lower_block ( body, false ) ,
@@ -4703,105 +4797,6 @@ impl<'a> LoweringContext<'a> {
4703
4797
4704
4798
ExprKind :: Err => hir:: ExprKind :: Err ,
4705
4799
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
4800
// Desugar `ExprForLoop`
4806
4801
// from: `[opt_ident]: for <pat> in <head> <body>`
4807
4802
ExprKind :: ForLoop ( ref pat, ref head, ref body, opt_label) => {
@@ -5463,10 +5458,15 @@ impl<'a> LoweringContext<'a> {
5463
5458
)
5464
5459
}
5465
5460
5461
+ /// Constructs a `true` or `false` literal expression.
5462
+ fn expr_bool ( & mut self , span : Span , val : bool ) -> hir:: Expr {
5463
+ let lit = Spanned { span, node : LitKind :: Bool ( val) } ;
5464
+ self . expr ( span, hir:: ExprKind :: Lit ( lit) , ThinVec :: new ( ) )
5465
+ }
5466
+
5466
5467
/// Constructs a `true` or `false` literal pattern.
5467
5468
fn pat_bool ( & mut self , span : Span , val : bool ) -> P < hir:: Pat > {
5468
- let lit = Spanned { span, node : LitKind :: Bool ( val) } ;
5469
- let expr = self . expr ( span, hir:: ExprKind :: Lit ( lit) , ThinVec :: new ( ) ) ;
5469
+ let expr = self . expr_bool ( span, val) ;
5470
5470
self . pat ( span, hir:: PatKind :: Lit ( P ( expr) ) )
5471
5471
}
5472
5472
0 commit comments