@@ -4344,53 +4344,147 @@ impl<'a> LoweringContext<'a> {
43444344 let ohs = P ( self . lower_expr ( ohs) ) ;
43454345 hir:: ExprKind :: AddrOf ( m, ohs)
43464346 }
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.
43494382 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-
43564383 // `_ => else_block` where `else_block` is `{}` if there's `None`:
43574384 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 ) ,
43694388 } ;
43704389 let else_arm = self . arm ( hir_vec ! [ else_pat] , P ( else_expr) ) ;
43714390
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) ) ;
43784421
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+ }
43864487 }
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- } ) ,
43944488 ExprKind :: Loop ( ref body, opt_label) => self . with_loop_scope ( e. id , |this| {
43954489 hir:: ExprKind :: Loop (
43964490 this. lower_block ( body, false ) ,
@@ -4703,105 +4797,6 @@ impl<'a> LoweringContext<'a> {
47034797
47044798 ExprKind :: Err => hir:: ExprKind :: Err ,
47054799
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-
48054800 // Desugar `ExprForLoop`
48064801 // from: `[opt_ident]: for <pat> in <head> <body>`
48074802 ExprKind :: ForLoop ( ref pat, ref head, ref body, opt_label) => {
@@ -5463,10 +5458,15 @@ impl<'a> LoweringContext<'a> {
54635458 )
54645459 }
54655460
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+
54665467 /// Constructs a `true` or `false` literal pattern.
54675468 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) ;
54705470 self . pat ( span, hir:: PatKind :: Lit ( P ( expr) ) )
54715471 }
54725472
0 commit comments