implement for loop desugaring

This commit is contained in:
Jorge Aparicio 2015-01-08 18:04:26 -05:00
parent a65d3f5b98
commit 9fdc0effd2
9 changed files with 115 additions and 115 deletions

View File

@ -264,42 +264,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
}
ast::ExprForLoop(ref pat, ref head, ref body, _) => {
//
// [pred]
// |
// v 1
// [head]
// |
// v 2
// [loopback] <--+ 7
// | |
// v 3 |
// +------[cond] |
// | | |
// | v 5 |
// | [pat] |
// | | |
// | v 6 |
// v 4 [body] -----+
// [expr]
//
// Note that `break` and `continue` statements
// may cause additional edges.
let head = self.expr(&**head, pred); // 1
let loopback = self.add_dummy_node(&[head]); // 2
let cond = self.add_dummy_node(&[loopback]); // 3
let expr_exit = self.add_node(expr.id, &[cond]); // 4
self.loop_scopes.push(LoopScope {
loop_id: expr.id,
continue_index: loopback,
break_index: expr_exit,
});
let pat = self.pat(&**pat, cond); // 5
let body = self.block(&**body, pat); // 6
self.add_contained_edge(body, loopback); // 7
self.loop_scopes.pop();
expr_exit
self.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
ast::ExprLoop(ref body, _) => {

View File

@ -538,21 +538,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
}
ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
// The pattern lives as long as the block.
debug!("walk_expr for loop case: blk id={}", blk.id);
self.consume_expr(&**head);
// Fetch the type of the value that the iteration yields to
// produce the pattern's categorized mutable type.
let pattern_type = return_if_err!(self.typer.node_ty(pat.id));
let blk_scope = region::CodeExtent::from_node_id(blk.id);
let pat_cmt = self.mc.cat_rvalue(pat.id,
pat.span,
ty::ReScope(blk_scope),
pattern_type);
self.walk_irrefutable_pat(pat_cmt, &**pat);
self.walk_block(&**blk);
self.tcx().sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
ast::ExprUnary(op, ref lhs) => {

View File

@ -491,18 +491,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::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 {:?}",
p_id, bm);
let name = path1.node;
ir.add_live_node_for_node(p_id, VarDefNode(sp));
ir.add_variable(Local(LocalInfo {
id: p_id,
ident: name
}));
});
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
visit::walk_expr(ir, expr);
ir.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
ast::ExprBinary(op, _, _) if ast_util::lazy_binop(op.node) => {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
@ -1035,8 +1024,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
let ln = self.propagate_through_loop(expr, ForLoop(&**pat), &**blk, succ);
self.propagate_through_expr(&**head, ln)
self.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
// Note that labels have been resolved, so we don't need to look
@ -1476,14 +1464,6 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
visit::walk_expr(this, expr);
}
ast::ExprForLoop(ref pat, _, _, _) => {
this.pat_bindings(&**pat, |this, ln, var, sp, id| {
this.warn_about_unused(sp, id, ln, var);
});
visit::walk_expr(this, expr);
}
// no correctness conditions related to liveness
ast::ExprCall(..) | ast::ExprMethodCall(..) | ast::ExprIf(..) |
ast::ExprMatch(..) | ast::ExprWhile(..) | ast::ExprLoop(..) |
@ -1503,6 +1483,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ast::ExprWhileLet(..) => {
this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(..) => {
this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
}
}

View File

@ -536,8 +536,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
ast::ExprInlineAsm(..) | ast::ExprBox(..) |
ast::ExprForLoop(..) => {
ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
@ -547,6 +546,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
ast::ExprWhileLet(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
}
}

View File

@ -4582,6 +4582,10 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(..) => {
tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
RvalueDpsExpr
}
@ -4619,8 +4623,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprLoop(..) |
ast::ExprAssign(..) |
ast::ExprInlineAsm(..) |
ast::ExprAssignOp(..) |
ast::ExprForLoop(..) => {
ast::ExprAssignOp(..) => {
RvalueStmtExpr
}

View File

@ -288,9 +288,9 @@ mod svh_visitor {
ExprStruct(..) => SawExprStruct,
ExprRepeat(..) => SawExprRepeat,
ExprParen(..) => SawExprParen,
ExprForLoop(..) => SawExprForLoop,
// just syntactic artifacts, expanded away by time of SVH.
ExprForLoop(..) => unreachable!(),
ExprIfLet(..) => unreachable!(),
ExprWhileLet(..) => unreachable!(),
ExprMac(..) => unreachable!(),

View File

@ -3627,24 +3627,9 @@ fn create_scope_map(cx: &CrateContext,
Found unexpanded while-let.");
}
ast::ExprForLoop(ref pattern, ref head, ref body, _) => {
walk_expr(cx, &**head, scope_stack, scope_map);
with_new_scope(cx,
exp.span,
scope_stack,
scope_map,
|cx, scope_stack, scope_map| {
scope_map.insert(exp.id,
scope_stack.last()
.unwrap()
.scope_metadata);
walk_pattern(cx,
&**pattern,
scope_stack,
scope_map);
walk_block(cx, &**body, scope_stack, scope_map);
})
ast::ExprForLoop(..) => {
cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
Found unexpanded for loop.");
}
ast::ExprMac(_) => {

View File

@ -3762,22 +3762,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
ast::ExprWhileLet(..) => {
tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(ref pat, ref head, ref block, _) => {
check_expr(fcx, &**head);
let typ = lookup_method_for_for_loop(fcx, &**head, expr.id);
vtable::select_new_fcx_obligations(fcx);
debug!("ExprForLoop each item has type {}",
fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx()));
let pcx = pat_ctxt {
fcx: fcx,
map: pat_id_map(&tcx.def_map, &**pat),
};
_match::check_pat(&pcx, &**pat, typ);
check_block_no_value(fcx, &**block);
fcx.write_nil(id);
ast::ExprForLoop(..) => {
tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
ast::ExprLoop(ref body, _) => {
check_block_no_value(fcx, &**body);

View File

@ -225,11 +225,101 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
}
// Desugar ExprForLoop
// From: `[opt_ident]: for <pat> in <head> <body>`
ast::ExprForLoop(pat, head, body, opt_ident) => {
let pat = fld.fold_pat(pat);
// to:
//
// match ::std::iter::IntoIterator::into_iter(<head>) {
// mut iter => {
// [opt_ident]: loop {
// match ::std::iter::Iterator::next(&mut iter) {
// ::std::option::Option::Some(<pat>) => <body>,
// ::std::option::Option::None => break
// }
// }
// }
// }
// expand <head>
let head = fld.fold_expr(head);
let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
fld.cx.expr(span, ast::ExprForLoop(pat, head, body, opt_ident))
// create an hygienic ident
let iter = {
let ident = fld.cx.ident_of("iter");
let new_ident = fresh_name(&ident);
let rename = (ident, new_ident);
let mut rename_list = vec![rename];
let mut rename_fld = IdentRenamer{ renames: &mut rename_list };
rename_fld.fold_ident(ident)
};
let pat_span = pat.span;
// `:;std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
let body_expr = fld.cx.expr_block(body);
let some_pat = fld.cx.pat_some(pat_span, pat);
fld.cx.arm(pat_span, vec![some_pat], body_expr)
};
// `::std::option::Option::None => break`
let break_arm = {
let break_expr = fld.cx.expr_break(span);
fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr)
};
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
let match_expr = {
let next_path = {
let strs = vec![
fld.cx.ident_of("std"),
fld.cx.ident_of("iter"),
fld.cx.ident_of("Iterator"),
fld.cx.ident_of("next"),
];
fld.cx.path_global(span, strs)
};
let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter));
let next_expr =
fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]);
let arms = vec![pat_arm, break_arm];
// FIXME(japaric) This should use `ForLoopDesugar` as MatchSource
fld.cx.expr_match(pat_span, next_expr, arms)
};
// `[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 loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
// `mut iter => { ... }`
let iter_arm = {
let iter_pat =
fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable));
fld.cx.arm(span, vec![iter_pat], loop_expr)
};
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
let into_iter_path = {
let strs = vec![
fld.cx.ident_of("std"),
fld.cx.ident_of("iter"),
fld.cx.ident_of("IntoIterator"),
fld.cx.ident_of("into_iter"),
];
fld.cx.path_global(span, strs)
};
fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
};
fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
}
ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => {