Skip to content

Commit ac200e6

Browse files
committed
Desugar 'if let' into the appropriate 'match'
1 parent 34301b7 commit ac200e6

File tree

9 files changed

+108
-0
lines changed

9 files changed

+108
-0
lines changed

src/librustc/middle/cfg/construct.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ impl<'a> CFGBuilder<'a> {
225225
self.add_node(expr.id, [then_exit, else_exit]) // 4, 5
226226
}
227227

228+
ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"),
229+
228230
ast::ExprWhile(ref cond, ref body) => {
229231
//
230232
// [pred]

src/librustc/middle/expr_use_visitor.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
356356
}
357357
}
358358

359+
ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"),
360+
359361
ast::ExprMatch(ref discr, ref arms) => {
360362
// treatment of the discriminant is handled while
361363
// walking the arms:

src/librustc/middle/liveness.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
491491
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
492492
visit::walk_expr(ir, expr, ());
493493
}
494+
ExprIfLet(..) => fail!("non-desugared ExprIfLet"),
494495
ExprForLoop(ref pat, _, _, _) => {
495496
pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
496497
debug!("adding local variable {} from for loop with bm {:?}",
@@ -1017,6 +1018,8 @@ impl<'a> Liveness<'a> {
10171018
self.propagate_through_expr(&**cond, ln)
10181019
}
10191020

1021+
ExprIfLet(..) => fail!("non-desugared ExprIfLet"),
1022+
10201023
ExprWhile(ref cond, ref blk) => {
10211024
self.propagate_through_loop(expr,
10221025
WhileLoop(cond.clone()),
@@ -1458,6 +1461,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
14581461
ExprPath(..) | ExprBox(..) | ExprForLoop(..) => {
14591462
visit::walk_expr(this, expr, ());
14601463
}
1464+
ExprIfLet(..) => fail!("non-desugared ExprIfLet")
14611465
}
14621466
}
14631467

src/librustc/middle/mem_categorization.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
514514
ast::ExprForLoop(..) => {
515515
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
516516
}
517+
518+
ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet")
517519
}
518520
}
519521

src/librustc/middle/trans/debuginfo.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3603,6 +3603,11 @@ fn populate_scope_map(cx: &CrateContext,
36033603
}
36043604
}
36053605

3606+
ast::ExprIfLet(..) => {
3607+
cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
3608+
Found unexpanded if-let.");
3609+
}
3610+
36063611
ast::ExprWhile(ref cond_exp, ref loop_body) => {
36073612
walk_expr(cx, &**cond_exp, scope_stack, scope_map);
36083613

src/librustc/middle/ty.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3429,6 +3429,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
34293429
RvalueDpsExpr
34303430
}
34313431

3432+
ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"),
3433+
34323434
ast::ExprLit(lit) if lit_is_str(lit) => {
34333435
RvalueDpsExpr
34343436
}

src/librustc/middle/typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3430,6 +3430,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
34303430
check_then_else(fcx, &**cond, &**then_blk, opt_else_expr.clone(),
34313431
id, expr.span, expected);
34323432
}
3433+
ast::ExprIfLet(..) => fail!("non-desugared ExprIfLet"),
34333434
ast::ExprWhile(ref cond, ref body) => {
34343435
check_expr_has_type(fcx, &**cond, ty::mk_bool());
34353436
check_block_no_value(fcx, &**body);

src/librustc_back/svh.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ mod svh_visitor {
291291
ExprForLoop(..) => SawExprForLoop,
292292

293293
// just syntactic artifacts, expanded away by time of SVH.
294+
ExprIfLet(..) => unreachable!(),
294295
ExprMac(..) => unreachable!(),
295296
}
296297
}

src/libsyntax/ext/expand.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,95 @@ fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
6262
}
6363
}
6464

65+
// Desugar ExprIfLet
66+
// From: `if let <pat> = <expr> <body> [<elseopt>]`
67+
ast::ExprIfLet(pat, expr, body, mut elseopt) => {
68+
let span = e.span;
69+
70+
// to:
71+
//
72+
// match <expr> {
73+
// <pat> => <body>,
74+
// [_ if <elseopt_if_cond> => <elseopt_if_body>,]
75+
// _ => [<elseopt> | ()]
76+
// }
77+
78+
// `<pat> => <body>`
79+
let pat_arm = {
80+
let body_expr = fld.cx.expr_block(body);
81+
fld.cx.arm(pat.span, vec![pat], body_expr)
82+
};
83+
84+
// `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
85+
let else_if_arms = {
86+
let mut arms = vec![];
87+
loop {
88+
// NOTE: replace with 'if let' after snapshot
89+
match elseopt {
90+
Some(els) => match els.node {
91+
// else if
92+
ast::ExprIf(cond, then, elseopt_) => {
93+
let pat_under = fld.cx.pat_wild(span);
94+
elseopt = elseopt_;
95+
arms.push(ast::Arm {
96+
attrs: vec![],
97+
pats: vec![pat_under],
98+
guard: Some(cond),
99+
body: fld.cx.expr_block(then)
100+
});
101+
}
102+
_ => break
103+
},
104+
None => break
105+
}
106+
}
107+
arms
108+
};
109+
110+
// `_ => [<elseopt> | ()]`
111+
let else_arm = {
112+
let pat_under = fld.cx.pat_wild(span);
113+
let else_expr = match elseopt {
114+
Some(els) => els,
115+
None => fld.cx.expr_lit(span, ast::LitNil)
116+
};
117+
fld.cx.arm(span, vec![pat_under], else_expr)
118+
};
119+
120+
let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
121+
arms.push(pat_arm);
122+
arms.push_all_move(else_if_arms);
123+
arms.push(else_arm);
124+
125+
let match_expr = fld.cx.expr_match(span, expr, arms);
126+
fld.fold_expr(match_expr)
127+
}
128+
129+
// Desugar support for ExprIfLet in the ExprIf else position
130+
ast::ExprIf(cond, blk, mut elseopt) => {
131+
// NOTE: replace with 'if let' after snapshot
132+
match elseopt {
133+
Some(els) => match els.node {
134+
ast::ExprIfLet(..) => {
135+
// wrap the if-let expr in a block
136+
let blk = P(ast::Block {
137+
view_items: vec![],
138+
stmts: vec![],
139+
expr: Some(els),
140+
id: ast::DUMMY_NODE_ID,
141+
rules: ast::DefaultBlock,
142+
span: els.span
143+
});
144+
elseopt = Some(fld.cx.expr_block(blk));
145+
}
146+
_ => ()
147+
},
148+
None => ()
149+
};
150+
let if_expr = fld.cx.expr(e.span, ast::ExprIf(cond, blk, elseopt));
151+
noop_fold_expr(if_expr, fld)
152+
}
153+
65154
ast::ExprLoop(loop_block, opt_ident) => {
66155
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
67156
fld.cx.expr(e.span, ast::ExprLoop(loop_block, opt_ident))

0 commit comments

Comments
 (0)