@@ -61,6 +61,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
61
61
use syntax:: print:: pprust;
62
62
use syntax:: ptr:: P ;
63
63
use syntax:: source_map:: { self , respan, CompilerDesugaringKind , Spanned } ;
64
+ use syntax:: source_map:: CompilerDesugaringKind :: IfTemporary ;
64
65
use syntax:: std_inject;
65
66
use syntax:: symbol:: { keywords, Symbol } ;
66
67
use syntax:: tokenstream:: { TokenStream , TokenTree } ;
@@ -4035,32 +4036,44 @@ impl<'a> LoweringContext<'a> {
4035
4036
}
4036
4037
// More complicated than you might expect because the else branch
4037
4038
// 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 {
4041
4051
ExprKind :: IfLet ( ..) => {
4042
4052
// 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 ( ) )
4055
4056
}
4056
- _ => P ( self . lower_expr ( els) ) ,
4057
+ _ => self . lower_expr ( els) ,
4057
4058
}
4058
- } ) ;
4059
+ } ;
4060
+ let else_arm = self . arm ( hir_vec ! [ else_pat] , P ( else_expr) ) ;
4059
4061
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);
4062
4069
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
+ )
4064
4077
}
4065
4078
ExprKind :: While ( ref cond, ref body, opt_label) => self . with_loop_scope ( e. id , |this| {
4066
4079
hir:: ExprKind :: While (
@@ -4654,6 +4667,8 @@ impl<'a> LoweringContext<'a> {
4654
4667
4655
4668
// `{ let _result = ...; _result }`
4656
4669
// 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`.
4657
4672
let result_ident = self . str_to_ident ( "_result" ) ;
4658
4673
let ( let_stmt, let_stmt_binding) =
4659
4674
self . stmt_let ( e. span , false , result_ident, match_expr) ;
@@ -5023,6 +5038,26 @@ impl<'a> LoweringContext<'a> {
5023
5038
)
5024
5039
}
5025
5040
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
+
5026
5061
fn expr_match (
5027
5062
& mut self ,
5028
5063
span : Span ,
@@ -5051,31 +5086,28 @@ impl<'a> LoweringContext<'a> {
5051
5086
}
5052
5087
}
5053
5088
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
+
5054
5103
fn stmt_let_pat (
5055
5104
& mut self ,
5056
5105
sp : Span ,
5057
5106
ex : Option < P < hir:: Expr > > ,
5058
5107
pat : P < hir:: Pat > ,
5059
5108
source : hir:: LocalSource ,
5060
5109
) -> 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)
5079
5111
}
5080
5112
5081
5113
fn stmt_let (
@@ -5097,6 +5129,11 @@ impl<'a> LoweringContext<'a> {
5097
5129
)
5098
5130
}
5099
5131
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
+
5100
5137
fn block_expr ( & mut self , expr : P < hir:: Expr > ) -> hir:: Block {
5101
5138
self . block_all ( expr. span , hir:: HirVec :: new ( ) , Some ( expr) )
5102
5139
}
@@ -5119,6 +5156,13 @@ impl<'a> LoweringContext<'a> {
5119
5156
}
5120
5157
}
5121
5158
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
+
5122
5166
fn pat_ok ( & mut self , span : Span , pat : P < hir:: Pat > ) -> P < hir:: Pat > {
5123
5167
self . pat_std_enum ( span, & [ "result" , "Result" , "Ok" ] , hir_vec ! [ pat] )
5124
5168
}
@@ -5209,6 +5253,18 @@ impl<'a> LoweringContext<'a> {
5209
5253
path
5210
5254
}
5211
5255
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
+
5212
5268
fn ty_path ( & mut self , id : LoweredNodeId , span : Span , qpath : hir:: QPath ) -> hir:: Ty {
5213
5269
let mut id = id;
5214
5270
let node = match qpath {
0 commit comments