implement for loop desugaring
This commit is contained in:
parent
a65d3f5b98
commit
9fdc0effd2
@ -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, _) => {
|
||||
|
@ -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) => {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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!(),
|
||||
|
@ -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(_) => {
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user