@@ -61,6 +61,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
6161use syntax:: print:: pprust;
6262use syntax:: ptr:: P ;
6363use syntax:: source_map:: { self , respan, CompilerDesugaringKind , Spanned } ;
64+ use syntax:: source_map:: CompilerDesugaringKind :: IfTemporary ;
6465use syntax:: std_inject;
6566use syntax:: symbol:: { keywords, Symbol } ;
6667use syntax:: tokenstream:: { TokenStream , TokenTree } ;
@@ -4035,32 +4036,44 @@ impl<'a> LoweringContext<'a> {
40354036 }
40364037 // More complicated than you might expect because the else branch
40374038 // might be `if let`.
4038- ExprKind :: If ( ref cond, ref blk, ref else_opt) => {
4039- let else_opt = else_opt. as_ref ( ) . map ( |els| {
4040- match els. node {
4039+ ExprKind :: If ( ref cond, ref then, ref else_opt) => {
4040+ // `true => then`:
4041+ let then_pat = self . pat_bool ( e. span , true ) ;
4042+ let then_blk = self . lower_block ( then, false ) ;
4043+ let then_expr = self . expr_block ( then_blk, ThinVec :: new ( ) ) ;
4044+ let then_arm = self . arm ( hir_vec ! [ then_pat] , P ( then_expr) ) ;
4045+
4046+ // `_ => else_block` where `else_block` is `()` if there's `None`:
4047+ let else_pat = self . pat_wild ( e. span ) ;
4048+ let else_expr = match else_opt {
4049+ None => self . expr_block_empty ( e. span ) ,
4050+ Some ( els) => match els. node {
40414051 ExprKind :: IfLet ( ..) => {
40424052 // Wrap the `if let` expr in a block.
4043- let span = els. span ;
4044- let els = P ( self . lower_expr ( els) ) ;
4045- let LoweredNodeId { node_id : _, hir_id } = self . next_id ( ) ;
4046- let blk = P ( hir:: Block {
4047- stmts : hir_vec ! [ ] ,
4048- expr : Some ( els) ,
4049- hir_id,
4050- rules : hir:: DefaultBlock ,
4051- span,
4052- targeted_by_break : false ,
4053- } ) ;
4054- P ( self . expr_block ( blk, ThinVec :: new ( ) ) )
4053+ let els = self . lower_expr ( els) ;
4054+ let blk = self . block_all ( els. span , hir_vec ! [ ] , Some ( P ( els) ) ) ;
4055+ self . expr_block ( P ( blk) , ThinVec :: new ( ) )
40554056 }
4056- _ => P ( self . lower_expr ( els) ) ,
4057+ _ => self . lower_expr ( els) ,
40574058 }
4058- } ) ;
4059+ } ;
4060+ let else_arm = self . arm ( hir_vec ! [ else_pat] , P ( else_expr) ) ;
40594061
4060- let then_blk = self . lower_block ( blk, false ) ;
4061- let then_expr = self . expr_block ( then_blk, ThinVec :: new ( ) ) ;
4062+ // Lower condition:
4063+ let span_block = self . mark_span_with_reason ( IfTemporary , cond. span , None ) ;
4064+ let cond = self . lower_expr ( cond) ;
4065+ //let bool_ty = Some(P(self.ty_bool(e.span)));
4066+ // FIXME(centril, oli-obk): This is silly but we must wrap the condition expression
4067+ // in a block `{ let _t = $cond; _t }` to preserve drop semantics.
4068+ let cond = self . expr_temp ( span_block, P ( cond) ) ; //, bool_ty);
40624069
4063- hir:: ExprKind :: If ( P ( self . lower_expr ( cond) ) , P ( then_expr) , else_opt)
4070+ hir:: ExprKind :: Match (
4071+ P ( cond) ,
4072+ vec ! [ then_arm, else_arm] . into ( ) ,
4073+ hir:: MatchSource :: IfDesugar {
4074+ contains_else_clause : else_opt. is_some ( )
4075+ } ,
4076+ )
40644077 }
40654078 ExprKind :: While ( ref cond, ref body, opt_label) => self . with_loop_scope ( e. id , |this| {
40664079 hir:: ExprKind :: While (
@@ -4654,6 +4667,8 @@ impl<'a> LoweringContext<'a> {
46544667
46554668 // `{ let _result = ...; _result }`
46564669 // Underscore prevents an `unused_variables` lint if the head diverges.
4670+ // https://github.com/rust-lang/rust/commit/b445bf2bd1139236fd815bf93610ddaf17726111
4671+ // FIXME(centril): Consider optimizing with `ExprKind::Use`.
46574672 let result_ident = self . str_to_ident ( "_result" ) ;
46584673 let ( let_stmt, let_stmt_binding) =
46594674 self . stmt_let ( e. span , false , result_ident, match_expr) ;
@@ -5023,6 +5038,26 @@ impl<'a> LoweringContext<'a> {
50235038 )
50245039 }
50255040
5041+ /// Wrap the given `expr` in `{ let _tmp[: ty]? = expr; _tmp }`.
5042+ /// This can be important for drop order of e.g. `if expr { .. }`.
5043+ fn expr_temp (
5044+ & mut self ,
5045+ span : Span ,
5046+ //source: hir::LocalSource,
5047+ expr : P < hir:: Expr > ,
5048+ //ty: Option<P<hir::Ty>>
5049+ ) -> hir:: Expr {
5050+ /*
5051+ let tident = self.str_to_ident("_tmp");
5052+ let (tpat, tpat_nid) = self.pat_ident(span, tident);
5053+ let tstmt = self.stmt_let_pat_ty(span, ty, Some(expr), tpat, source);
5054+ let access = self.expr_ident(span, tident, tpat_nid);
5055+ let block = self.block_all(span, hir_vec![tstmt], Some(P(access)));
5056+ self.expr_block(P(block), ThinVec::new())
5057+ */
5058+ self . expr ( span, hir:: ExprKind :: Use ( expr) , ThinVec :: new ( ) )
5059+ }
5060+
50265061 fn expr_match (
50275062 & mut self ,
50285063 span : Span ,
@@ -5051,31 +5086,28 @@ impl<'a> LoweringContext<'a> {
50515086 }
50525087 }
50535088
5089+ fn stmt_let_pat_ty (
5090+ & mut self ,
5091+ span : Span ,
5092+ ty : Option < P < hir:: Ty > > ,
5093+ init : Option < P < hir:: Expr > > ,
5094+ pat : P < hir:: Pat > ,
5095+ source : hir:: LocalSource ,
5096+ ) -> hir:: Stmt {
5097+ let LoweredNodeId { node_id : _, hir_id } = self . next_id ( ) ;
5098+ let local = hir:: Local { pat, ty, init, hir_id, span, source, attrs : ThinVec :: new ( ) } ;
5099+ let LoweredNodeId { node_id : _, hir_id } = self . next_id ( ) ;
5100+ hir:: Stmt { span, hir_id, node : hir:: StmtKind :: Local ( P ( local) ) }
5101+ }
5102+
50545103 fn stmt_let_pat (
50555104 & mut self ,
50565105 sp : Span ,
50575106 ex : Option < P < hir:: Expr > > ,
50585107 pat : P < hir:: Pat > ,
50595108 source : hir:: LocalSource ,
50605109 ) -> hir:: Stmt {
5061- let LoweredNodeId { node_id : _, hir_id } = self . next_id ( ) ;
5062-
5063- let local = hir:: Local {
5064- pat,
5065- ty : None ,
5066- init : ex,
5067- hir_id,
5068- span : sp,
5069- attrs : ThinVec :: new ( ) ,
5070- source,
5071- } ;
5072-
5073- let LoweredNodeId { node_id : _, hir_id } = self . next_id ( ) ;
5074- hir:: Stmt {
5075- hir_id,
5076- node : hir:: StmtKind :: Local ( P ( local) ) ,
5077- span : sp
5078- }
5110+ self . stmt_let_pat_ty ( sp, None , ex, pat, source)
50795111 }
50805112
50815113 fn stmt_let (
@@ -5097,6 +5129,11 @@ impl<'a> LoweringContext<'a> {
50975129 )
50985130 }
50995131
5132+ fn expr_block_empty ( & mut self , span : Span ) -> hir:: Expr {
5133+ let blk = self . block_all ( span, hir_vec ! [ ] , None ) ;
5134+ self . expr_block ( P ( blk) , ThinVec :: new ( ) )
5135+ }
5136+
51005137 fn block_expr ( & mut self , expr : P < hir:: Expr > ) -> hir:: Block {
51015138 self . block_all ( expr. span , hir:: HirVec :: new ( ) , Some ( expr) )
51025139 }
@@ -5119,6 +5156,13 @@ impl<'a> LoweringContext<'a> {
51195156 }
51205157 }
51215158
5159+ /// Constructs a `true` or `false` literal pattern.
5160+ fn pat_bool ( & mut self , span : Span , val : bool ) -> P < hir:: Pat > {
5161+ let lit = Spanned { span, node : LitKind :: Bool ( val) } ;
5162+ let expr = self . expr ( span, hir:: ExprKind :: Lit ( lit) , ThinVec :: new ( ) ) ;
5163+ self . pat ( span, hir:: PatKind :: Lit ( P ( expr) ) )
5164+ }
5165+
51225166 fn pat_ok ( & mut self , span : Span , pat : P < hir:: Pat > ) -> P < hir:: Pat > {
51235167 self . pat_std_enum ( span, & [ "result" , "Result" , "Ok" ] , hir_vec ! [ pat] )
51245168 }
@@ -5209,6 +5253,18 @@ impl<'a> LoweringContext<'a> {
52095253 path
52105254 }
52115255
5256+ /*
5257+ /// Constructs and returns the type `bool`.
5258+ fn ty_bool(&mut self, span: Span) -> hir::Ty {
5259+ let id = self.next_id();
5260+ self.ty_path(id, span, hir::QPath::Resolved(None, P(hir::Path {
5261+ span,
5262+ segments: hir_vec![],
5263+ def: Def::PrimTy(hir::PrimTy::Bool)
5264+ })))
5265+ }
5266+ */
5267+
52125268 fn ty_path ( & mut self , id : LoweredNodeId , span : Span , qpath : hir:: QPath ) -> hir:: Ty {
52135269 let mut id = id;
52145270 let node = match qpath {
0 commit comments