From 9fdc0effd292b097ae487ec4d927ca15102c5791 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 8 Jan 2015 18:04:26 -0500 Subject: [PATCH] implement for loop desugaring --- src/librustc/middle/cfg/construct.rs | 37 +-------- src/librustc/middle/expr_use_visitor.rs | 16 +--- src/librustc/middle/liveness.rs | 27 ++----- src/librustc/middle/mem_categorization.rs | 6 +- src/librustc/middle/ty.rs | 7 +- src/librustc_back/svh.rs | 2 +- src/librustc_trans/trans/debuginfo.rs | 21 +---- src/librustc_typeck/check/mod.rs | 18 +---- src/libsyntax/ext/expand.rs | 96 ++++++++++++++++++++++- 9 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 6162f61fde1..3f6c19680e7 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -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, _) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0d543ca7beb..b09dac6b1dc 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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) => { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index f6a51004eb6..d91816d1c14 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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"); + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 1be1bfa6730..7de6b70b159 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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"); + } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 44615f19d94..55cf5835bd7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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 } diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index aef4f7a896b..aefed4b87b4 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -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!(), diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index ce9af3162a0..7aa0a30b455 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -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(_) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d78b819065a..14c976c6ae8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index acf0fe7f6cd..357bd2c17ab 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -225,11 +225,101 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) } + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` ast::ExprForLoop(pat, head, body, opt_ident) => { - let pat = fld.fold_pat(pat); + // to: + // + // match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // } + + // expand 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() => ` + 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() { ... }` + 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) => {