diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index b268c2a7a51..1f0171de351 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -222,6 +222,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_node(expr.id, [then_exit, else_exit]) // 4, 5 } + ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"), + ast::ExprWhile(ref cond, ref body, _) => { // // [pred] diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 81994ee64a8..875416feb2e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -374,6 +374,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { } } + ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"), + ast::ExprMatch(ref discr, ref arms) => { let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr)); self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b6893a6a3b4..061f110afa9 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -481,6 +481,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); visit::walk_expr(ir, expr); } + ExprIfLet(..) => fail!("non-desugared ExprIfLet"), ExprForLoop(ref pat, _, _, _) => { pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| { debug!("adding local variable {} from for loop with bm {:?}", @@ -1011,6 +1012,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&**cond, ln) } + ExprIfLet(..) => fail!("non-desugared ExprIfLet"), + ExprWhile(ref cond, ref blk, _) => { self.propagate_through_loop(expr, WhileLoop(&**cond), &**blk, succ) } @@ -1470,6 +1473,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ExprPath(..) | ExprBox(..) => { visit::walk_expr(this, expr); } + ExprIfLet(..) => fail!("non-desugared ExprIfLet") } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b831dd6847..d5ada0c5411 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -505,6 +505,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ast::ExprForLoop(..) => { Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } + + ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet") } } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 7a0e5aea7ff..5221faa598c 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -3576,6 +3576,11 @@ fn populate_scope_map(cx: &CrateContext, } } + ast::ExprIfLet(..) => { + cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \ + Found unexpanded if-let."); + } + ast::ExprWhile(ref cond_exp, ref loop_body, _) => { walk_expr(cx, &**cond_exp, scope_stack, scope_map); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 875a79373a6..b55c3039ac8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3634,6 +3634,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLit(ref lit) if lit_is_str(&**lit) => { RvalueDpsExpr } + ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"), ast::ExprCast(..) => { match tcx.node_types.borrow().find(&(expr.id as uint)) { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0bf22d97345..56620383408 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -4106,6 +4106,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_then_else(fcx, &**cond, &**then_blk, opt_else_expr.as_ref().map(|e| &**e), id, expr.span, expected); } + ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"), ast::ExprWhile(ref cond, ref body, _) => { check_expr_has_type(fcx, &**cond, ty::mk_bool()); check_block_no_value(fcx, &**body); diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index f98a2dac084..394833372a6 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -293,6 +293,7 @@ mod svh_visitor { ExprForLoop(..) => SawExprForLoop, // just syntactic artifacts, expanded away by time of SVH. + ExprIfLet(..) => unreachable!(), ExprMac(..) => unreachable!(), } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9f3df1a7623..341be15b739 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -39,7 +39,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. - ExprMac(mac) => { + ast::ExprMac(mac) => { let expanded_expr = match expand_mac_invoc(mac, span, |r| r.make_expr(), mark_expr, fld) { @@ -67,6 +67,95 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident)) } + // Desugar ExprIfLet + // From: `if let = []` + ast::ExprIfLet(pat, expr, body, mut elseopt) => { + let span = e.span; + + // to: + // + // match { + // => , + // [_ if => ,] + // _ => [ | ()] + // } + + // ` => ` + let pat_arm = { + let body_expr = fld.cx.expr_block(body); + fld.cx.arm(pat.span, vec![pat], body_expr) + }; + + // `[_ if => ,]` + let else_if_arms = { + let mut arms = vec![]; + loop { + // NOTE: replace with 'if let' after snapshot + match elseopt { + Some(els) => match els.node { + // else if + ast::ExprIf(cond, then, elseopt_) => { + let pat_under = fld.cx.pat_wild(span); + elseopt = elseopt_; + arms.push(ast::Arm { + attrs: vec![], + pats: vec![pat_under], + guard: Some(cond), + body: fld.cx.expr_block(then) + }); + } + _ => break + }, + None => break + } + } + arms + }; + + // `_ => [ | ()]` + let else_arm = { + let pat_under = fld.cx.pat_wild(span); + let else_expr = match elseopt { + Some(els) => els, + None => fld.cx.expr_lit(span, ast::LitNil) + }; + fld.cx.arm(span, vec![pat_under], else_expr) + }; + + let mut arms = Vec::with_capacity(else_if_arms.len() + 2); + arms.push(pat_arm); + arms.push_all_move(else_if_arms); + arms.push(else_arm); + + let match_expr = fld.cx.expr_match(span, expr, arms); + fld.fold_expr(match_expr) + } + + // Desugar support for ExprIfLet in the ExprIf else position + ast::ExprIf(cond, blk, mut elseopt) => { + // NOTE: replace with 'if let' after snapshot + match elseopt { + Some(els) => match els.node { + ast::ExprIfLet(..) => { + // wrap the if-let expr in a block + let blk = P(ast::Block { + view_items: vec![], + stmts: vec![], + expr: Some(els), + id: ast::DUMMY_NODE_ID, + rules: ast::DefaultBlock, + span: els.span + }); + elseopt = Some(fld.cx.expr_block(blk)); + } + _ => () + }, + None => () + }; + let if_expr = fld.cx.expr(e.span, ast::ExprIf(cond, blk, elseopt)); + noop_fold_expr(if_expr, fld) + } + ast::ExprLoop(loop_block, opt_ident) => { let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))