if let and while let
This commit is contained in:
@@ -786,10 +786,28 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
|||||||
ExprAddrOf(m, ref ohs) => {
|
ExprAddrOf(m, ref ohs) => {
|
||||||
hir::ExprAddrOf(lower_mutability(lctx, m), lower_expr(lctx, ohs))
|
hir::ExprAddrOf(lower_mutability(lctx, m), lower_expr(lctx, ohs))
|
||||||
}
|
}
|
||||||
ExprIf(ref cond, ref tr, ref fl) => {
|
// More complicated than you might expect because the else branch
|
||||||
|
// might be `if let`.
|
||||||
|
ExprIf(ref cond, ref blk, ref else_opt) => {
|
||||||
|
let else_opt = else_opt.as_ref().map(|els| match els.node {
|
||||||
|
ExprIfLet(..) => {
|
||||||
|
// wrap the if-let expr in a block
|
||||||
|
let span = els.span;
|
||||||
|
let blk = P(hir::Block {
|
||||||
|
stmts: vec![],
|
||||||
|
expr: Some(lower_expr(lctx, els)),
|
||||||
|
id: lctx.next_id(),
|
||||||
|
rules: hir::DefaultBlock,
|
||||||
|
span: span
|
||||||
|
});
|
||||||
|
expr_block(lctx, blk)
|
||||||
|
}
|
||||||
|
_ => lower_expr(lctx, els)
|
||||||
|
});
|
||||||
|
|
||||||
hir::ExprIf(lower_expr(lctx, cond),
|
hir::ExprIf(lower_expr(lctx, cond),
|
||||||
lower_block(lctx, tr),
|
lower_block(lctx, blk),
|
||||||
fl.as_ref().map(|x| lower_expr(lctx, x)))
|
else_opt)
|
||||||
}
|
}
|
||||||
ExprWhile(ref cond, ref body, opt_ident) => {
|
ExprWhile(ref cond, ref body, opt_ident) => {
|
||||||
hir::ExprWhile(lower_expr(lctx, cond),
|
hir::ExprWhile(lower_expr(lctx, cond),
|
||||||
@@ -880,16 +898,123 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
|||||||
ExprInPlace(..) => {
|
ExprInPlace(..) => {
|
||||||
panic!("todo");
|
panic!("todo");
|
||||||
}
|
}
|
||||||
ExprIfLet(..) => {
|
|
||||||
panic!("todo");
|
// Desugar ExprIfLet
|
||||||
|
// From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
|
||||||
|
ExprIfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
|
||||||
|
// to:
|
||||||
|
//
|
||||||
|
// match <sub_expr> {
|
||||||
|
// <pat> => <body>,
|
||||||
|
// [_ if <else_opt_if_cond> => <else_opt_if_body>,]
|
||||||
|
// _ => [<else_opt> | ()]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// `<pat> => <body>`
|
||||||
|
let pat_arm = {
|
||||||
|
let body_expr = expr_block(lctx, lower_block(lctx, body));
|
||||||
|
arm(vec![lower_pat(lctx, pat)], body_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
// `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
|
||||||
|
let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e));
|
||||||
|
let else_if_arms = {
|
||||||
|
let mut arms = vec![];
|
||||||
|
loop {
|
||||||
|
let else_opt_continue = else_opt
|
||||||
|
.and_then(|els| els.and_then(|els| match els.node {
|
||||||
|
// else if
|
||||||
|
hir::ExprIf(cond, then, else_opt) => {
|
||||||
|
let pat_under = pat_wild(lctx, e.span);
|
||||||
|
arms.push(hir::Arm {
|
||||||
|
attrs: vec![],
|
||||||
|
pats: vec![pat_under],
|
||||||
|
guard: Some(cond),
|
||||||
|
body: expr_block(lctx, then)
|
||||||
|
});
|
||||||
|
else_opt.map(|else_opt| (else_opt, true))
|
||||||
}
|
}
|
||||||
ExprWhileLet(..) => {
|
_ => Some((P(els), false))
|
||||||
panic!("todo");
|
}));
|
||||||
|
match else_opt_continue {
|
||||||
|
Some((e, true)) => {
|
||||||
|
else_opt = Some(e);
|
||||||
|
}
|
||||||
|
Some((e, false)) => {
|
||||||
|
else_opt = Some(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
else_opt = None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arms
|
||||||
|
};
|
||||||
|
|
||||||
|
let contains_else_clause = else_opt.is_some();
|
||||||
|
|
||||||
|
// `_ => [<else_opt> | ()]`
|
||||||
|
let else_arm = {
|
||||||
|
let pat_under = pat_wild(lctx, e.span);
|
||||||
|
let else_expr = else_opt.unwrap_or_else(|| expr_tuple(lctx, e.span, vec![]));
|
||||||
|
arm(vec![pat_under], else_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
|
||||||
|
arms.push(pat_arm);
|
||||||
|
arms.extend(else_if_arms);
|
||||||
|
arms.push(else_arm);
|
||||||
|
|
||||||
|
let match_expr = expr(lctx,
|
||||||
|
e.span,
|
||||||
|
hir::ExprMatch(lower_expr(lctx, sub_expr), arms,
|
||||||
|
hir::MatchSource::IfLetDesugar {
|
||||||
|
contains_else_clause: contains_else_clause,
|
||||||
|
}));
|
||||||
|
return match_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desugar ExprWhileLet
|
||||||
|
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
|
||||||
|
ExprWhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
|
||||||
|
// to:
|
||||||
|
//
|
||||||
|
// [opt_ident]: loop {
|
||||||
|
// match <sub_expr> {
|
||||||
|
// <pat> => <body>,
|
||||||
|
// _ => break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// `<pat> => <body>`
|
||||||
|
let pat_arm = {
|
||||||
|
let body_expr = expr_block(lctx, lower_block(lctx, body));
|
||||||
|
arm(vec![lower_pat(lctx, pat)], body_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
// `_ => break`
|
||||||
|
let break_arm = {
|
||||||
|
let pat_under = pat_wild(lctx, e.span);
|
||||||
|
let break_expr = expr_break(lctx, e.span);
|
||||||
|
arm(vec![pat_under], break_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
// // `match <sub_expr> { ... }`
|
||||||
|
let arms = vec![pat_arm, break_arm];
|
||||||
|
let match_expr = expr(lctx,
|
||||||
|
e.span,
|
||||||
|
hir::ExprMatch(lower_expr(lctx, sub_expr), arms, hir::MatchSource::WhileLetDesugar));
|
||||||
|
|
||||||
|
// `[opt_ident]: loop { ... }`
|
||||||
|
let loop_block = block_expr(lctx, match_expr);
|
||||||
|
return expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desugar ExprForLoop
|
// Desugar ExprForLoop
|
||||||
// From: `[opt_ident]: for <pat> in <head> <body>`
|
// From: `[opt_ident]: for <pat> in <head> <body>`
|
||||||
ExprForLoop(ref pat, ref head, ref body, ref opt_ident) => {
|
ExprForLoop(ref pat, ref head, ref body, opt_ident) => {
|
||||||
// to:
|
// to:
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
@@ -952,7 +1077,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
|||||||
|
|
||||||
// `[opt_ident]: loop { ... }`
|
// `[opt_ident]: loop { ... }`
|
||||||
let loop_block = block_expr(lctx, match_expr);
|
let loop_block = block_expr(lctx, match_expr);
|
||||||
let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident.clone()));
|
let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
|
||||||
|
|
||||||
// `mut iter => { ... }`
|
// `mut iter => { ... }`
|
||||||
let iter_arm = {
|
let iter_arm = {
|
||||||
@@ -976,16 +1101,14 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
|||||||
|
|
||||||
// `{ let result = ...; result }`
|
// `{ let result = ...; result }`
|
||||||
let result_ident = token::gensym_ident("result");
|
let result_ident = token::gensym_ident("result");
|
||||||
let result = expr_block(lctx,
|
return expr_block(lctx,
|
||||||
block_all(lctx,
|
block_all(lctx,
|
||||||
e.span,
|
e.span,
|
||||||
vec![stmt_let(lctx,
|
vec![stmt_let(lctx, e.span,
|
||||||
e.span,
|
|
||||||
false,
|
false,
|
||||||
result_ident,
|
result_ident,
|
||||||
match_expr)],
|
match_expr)],
|
||||||
Some(expr_ident(lctx, e.span, result_ident))));
|
Some(expr_ident(lctx, e.span, result_ident))))
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprMac(_) => panic!("Shouldn't exist here"),
|
ExprMac(_) => panic!("Shouldn't exist here"),
|
||||||
@@ -1137,6 +1260,10 @@ fn expr_block(lctx: &LoweringContext, b: P<hir::Block>) -> P<hir::Expr> {
|
|||||||
expr(lctx, b.span, hir::ExprBlock(b))
|
expr(lctx, b.span, hir::ExprBlock(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: Vec<P<hir::Expr>>) -> P<hir::Expr> {
|
||||||
|
expr(lctx, sp, hir::ExprTup(exprs))
|
||||||
|
}
|
||||||
|
|
||||||
fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_) -> P<hir::Expr> {
|
fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_) -> P<hir::Expr> {
|
||||||
P(hir::Expr {
|
P(hir::Expr {
|
||||||
id: lctx.next_id(),
|
id: lctx.next_id(),
|
||||||
@@ -1208,6 +1335,10 @@ fn pat_ident_binding_mode(lctx: &LoweringContext,
|
|||||||
pat(lctx, span, pat_ident)
|
pat(lctx, span, pat_ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pat_wild(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
|
||||||
|
pat(lctx, span, hir::PatWild(hir::PatWildSingle))
|
||||||
|
}
|
||||||
|
|
||||||
fn pat(lctx: &LoweringContext, span: Span, pat: hir::Pat_) -> P<hir::Pat> {
|
fn pat(lctx: &LoweringContext, span: Span, pat: hir::Pat_) -> P<hir::Pat> {
|
||||||
P(hir::Pat { id: lctx.next_id(), node: pat, span: span })
|
P(hir::Pat { id: lctx.next_id(), node: pat, span: span })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,147 +212,11 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
|||||||
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
|
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desugar ExprWhileLet
|
|
||||||
// From: `[opt_ident]: while let <pat> = <expr> <body>`
|
|
||||||
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
|
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
|
||||||
// to:
|
let pat = fld.fold_pat(pat);
|
||||||
//
|
let expr = fld.fold_expr(expr);
|
||||||
// [opt_ident]: loop {
|
let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
|
||||||
// match <expr> {
|
fld.cx.expr(span, ast::ExprWhileLet(pat, expr, body, opt_ident))
|
||||||
// <pat> => <body>,
|
|
||||||
// _ => break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
push_compiler_expansion(fld, span, CompilerExpansionFormat::WhileLet);
|
|
||||||
|
|
||||||
// `<pat> => <body>`
|
|
||||||
let pat_arm = {
|
|
||||||
let body_expr = fld.cx.expr_block(body);
|
|
||||||
fld.cx.arm(pat.span, vec![pat], body_expr)
|
|
||||||
};
|
|
||||||
|
|
||||||
// `_ => break`
|
|
||||||
let break_arm = {
|
|
||||||
let pat_under = fld.cx.pat_wild(span);
|
|
||||||
let break_expr = fld.cx.expr_break(span);
|
|
||||||
fld.cx.arm(span, vec![pat_under], break_expr)
|
|
||||||
};
|
|
||||||
|
|
||||||
// `match <expr> { ... }`
|
|
||||||
let arms = vec![pat_arm, break_arm];
|
|
||||||
let match_expr = fld.cx.expr(span,
|
|
||||||
ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
|
|
||||||
|
|
||||||
// `[opt_ident]: loop { ... }`
|
|
||||||
let loop_block = fld.cx.block_expr(match_expr);
|
|
||||||
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
|
|
||||||
let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
|
|
||||||
fld.cx.bt_pop();
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Desugar ExprIfLet
|
|
||||||
// From: `if let <pat> = <expr> <body> [<elseopt>]`
|
|
||||||
ast::ExprIfLet(pat, expr, body, mut elseopt) => {
|
|
||||||
// to:
|
|
||||||
//
|
|
||||||
// match <expr> {
|
|
||||||
// <pat> => <body>,
|
|
||||||
// [_ if <elseopt_if_cond> => <elseopt_if_body>,]
|
|
||||||
// _ => [<elseopt> | ()]
|
|
||||||
// }
|
|
||||||
|
|
||||||
push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet);
|
|
||||||
|
|
||||||
// `<pat> => <body>`
|
|
||||||
let pat_arm = {
|
|
||||||
let body_expr = fld.cx.expr_block(body);
|
|
||||||
fld.cx.arm(pat.span, vec![pat], body_expr)
|
|
||||||
};
|
|
||||||
|
|
||||||
// `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
|
|
||||||
let else_if_arms = {
|
|
||||||
let mut arms = vec![];
|
|
||||||
loop {
|
|
||||||
let elseopt_continue = elseopt
|
|
||||||
.and_then(|els| els.and_then(|els| match els.node {
|
|
||||||
// else if
|
|
||||||
ast::ExprIf(cond, then, elseopt) => {
|
|
||||||
let pat_under = fld.cx.pat_wild(span);
|
|
||||||
arms.push(ast::Arm {
|
|
||||||
attrs: vec![],
|
|
||||||
pats: vec![pat_under],
|
|
||||||
guard: Some(cond),
|
|
||||||
body: fld.cx.expr_block(then)
|
|
||||||
});
|
|
||||||
elseopt.map(|elseopt| (elseopt, true))
|
|
||||||
}
|
|
||||||
_ => Some((P(els), false))
|
|
||||||
}));
|
|
||||||
match elseopt_continue {
|
|
||||||
Some((e, true)) => {
|
|
||||||
elseopt = Some(e);
|
|
||||||
}
|
|
||||||
Some((e, false)) => {
|
|
||||||
elseopt = Some(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
elseopt = None;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arms
|
|
||||||
};
|
|
||||||
|
|
||||||
let contains_else_clause = elseopt.is_some();
|
|
||||||
|
|
||||||
// `_ => [<elseopt> | ()]`
|
|
||||||
let else_arm = {
|
|
||||||
let pat_under = fld.cx.pat_wild(span);
|
|
||||||
let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![]));
|
|
||||||
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.extend(else_if_arms);
|
|
||||||
arms.push(else_arm);
|
|
||||||
|
|
||||||
let match_expr = fld.cx.expr(span,
|
|
||||||
ast::ExprMatch(expr, arms,
|
|
||||||
ast::MatchSource::IfLetDesugar {
|
|
||||||
contains_else_clause: contains_else_clause,
|
|
||||||
}));
|
|
||||||
let result = fld.fold_expr(match_expr);
|
|
||||||
fld.cx.bt_pop();
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Desugar support for ExprIfLet in the ExprIf else position
|
|
||||||
ast::ExprIf(cond, blk, elseopt) => {
|
|
||||||
let elseopt = elseopt.map(|els| els.and_then(|els| match els.node {
|
|
||||||
ast::ExprIfLet(..) => {
|
|
||||||
push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet);
|
|
||||||
// wrap the if-let expr in a block
|
|
||||||
let span = els.span;
|
|
||||||
let blk = P(ast::Block {
|
|
||||||
stmts: vec![],
|
|
||||||
expr: Some(P(els)),
|
|
||||||
id: ast::DUMMY_NODE_ID,
|
|
||||||
rules: ast::DefaultBlock,
|
|
||||||
span: span
|
|
||||||
});
|
|
||||||
let result = fld.cx.expr_block(blk);
|
|
||||||
fld.cx.bt_pop();
|
|
||||||
result
|
|
||||||
}
|
|
||||||
_ => P(els)
|
|
||||||
}));
|
|
||||||
let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt));
|
|
||||||
if_expr.map(|e| noop_fold_expr(e, fld))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ExprLoop(loop_block, opt_ident) => {
|
ast::ExprLoop(loop_block, opt_ident) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user