about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2015-09-28 15:00:15 +1300
committerNick Cameron <ncameron@mozilla.com>2015-10-09 11:53:41 +1300
commit20083c1e1f6916eb79e3d967c1c9ab63342c71ae (patch)
tree671e474800b5aacf481581cc46e700dcde46f808
parent56713a1684c22742a3a4d3d2b19fa09fa6832024 (diff)
downloadrust-20083c1e1f6916eb79e3d967c1c9ab63342c71ae.tar.gz
rust-20083c1e1f6916eb79e3d967c1c9ab63342c71ae.zip
Move `for` loop desugaring to lowering
-rw-r--r--mk/crates.mk4
-rw-r--r--src/librustc/middle/astencode.rs1
-rw-r--r--src/librustc/middle/ty/context.rs15
-rw-r--r--src/librustc/session/mod.rs11
-rw-r--r--src/librustc_driver/driver.rs32
-rw-r--r--src/librustc_driver/pretty.rs60
-rw-r--r--src/librustc_front/lowering.rs398
-rw-r--r--src/librustc_trans/save/dump_csv.rs2
-rw-r--r--src/librustc_trans/save/mod.rs10
-rw-r--r--src/librustc_typeck/coherence/mod.rs1
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/ext/expand.rs96
12 files changed, 420 insertions, 214 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index b424c1d8779..0213070d786 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -80,13 +80,13 @@ DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
 DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
 DEPS_rustc_resolve := rustc rustc_front log syntax
 DEPS_rustc_privacy := rustc rustc_front log syntax
+DEPS_rustc_front := std syntax log serialize
 DEPS_rustc_lint := rustc log syntax
-DEPS_rustc := syntax flate arena serialize getopts rbml \
+DEPS_rustc := syntax flate arena serialize getopts rbml rustc_front\
               log graphviz rustc_llvm rustc_back rustc_data_structures
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
 DEPS_rustc_platform_intrinsics := rustc rustc_llvm
 DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
-DEPS_rustc_front := std syntax log serialize
 DEPS_rustc_data_structures := std log serialize
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
                 test rustc_lint rustc_front
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 6c23307c677..985a517d8d9 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -36,6 +36,7 @@ use middle::subst;
 use middle::ty::{self, Ty};
 
 use syntax::{ast, ast_util, codemap};
+use syntax::ast::NodeIdAssigner;
 use syntax::codemap::Span;
 use syntax::ptr::P;
 
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index e506e5b2c07..830232cf373 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -219,7 +219,7 @@ pub struct ctxt<'tcx> {
     /// Common types, pre-interned for your convenience.
     pub types: CommonTypes<'tcx>,
 
-    pub sess: Session,
+    pub sess: &'tcx Session,
     pub def_map: DefMap,
 
     pub named_region_map: resolve_lifetime::NamedRegionMap,
@@ -443,7 +443,7 @@ impl<'tcx> ctxt<'tcx> {
     /// to the context. The closure enforces that the type context and any interned
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
     /// reference to the context, to allow formatting values that need it.
-    pub fn create_and_enter<F, R>(s: Session,
+    pub fn create_and_enter<F, R>(s: &'tcx Session,
                                  arenas: &'tcx CtxtArenas<'tcx>,
                                  def_map: DefMap,
                                  named_region_map: resolve_lifetime::NamedRegionMap,
@@ -452,7 +452,7 @@ impl<'tcx> ctxt<'tcx> {
                                  region_maps: RegionMaps,
                                  lang_items: middle::lang_items::LanguageItems,
                                  stability: stability::Index<'tcx>,
-                                 f: F) -> (Session, R)
+                                 f: F) -> R
                                  where F: FnOnce(&ctxt<'tcx>) -> R
     {
         let interner = RefCell::new(FnvHashMap());
@@ -556,7 +556,6 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
 
 pub mod tls {
     use middle::ty;
-    use session::Session;
 
     use std::fmt;
     use syntax::codemap;
@@ -574,17 +573,15 @@ pub mod tls {
         })
     }
 
-    pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
-                                                           -> (Session, R) {
-        let result = codemap::SPAN_DEBUG.with(|span_dbg| {
+    pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F) -> R {
+        codemap::SPAN_DEBUG.with(|span_dbg| {
             let original_span_debug = span_dbg.get();
             span_dbg.set(span_debug);
             let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
             let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
             span_dbg.set(original_span_debug);
             result
-        });
-        (tcx.sess, result)
+        })
     }
 
     pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 9d1674b74d1..1eb90580b48 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -15,7 +15,7 @@ use middle::dependency_format;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeMap, FnvHashMap};
 
-use syntax::ast::NodeId;
+use syntax::ast::{NodeId, NodeIdAssigner};
 use syntax::codemap::Span;
 use syntax::diagnostic::{self, Emitter};
 use syntax::diagnostics;
@@ -236,9 +236,6 @@ impl Session {
         }
         lints.insert(id, vec!((lint_id, sp, msg)));
     }
-    pub fn next_node_id(&self) -> ast::NodeId {
-        self.reserve_node_ids(1)
-    }
     pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
         let id = self.next_node_id.get();
 
@@ -317,6 +314,12 @@ impl Session {
     }
 }
 
+impl NodeIdAssigner for Session {
+    fn next_node_id(&self) -> NodeId {
+        self.reserve_node_ids(1)
+    }
+}
+
 fn split_msg_into_multilines(msg: &str) -> Option<String> {
     // Conditions for enabling multi-line errors:
     if !msg.contains("mismatched types") &&
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index a3055d6d67c..6f989811ed2 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -42,7 +42,7 @@ use std::ffi::{OsString, OsStr};
 use std::fs;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
-use syntax::ast;
+use syntax::ast::{self, NodeIdAssigner};
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
 use syntax::diagnostics;
@@ -71,7 +71,7 @@ pub fn compile_input(sess: Session,
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
-    let (sess, result) = {
+    let result = {
         let (outputs, expanded_crate, id) = {
             let krate = phase_1_parse_input(&sess, cfg, input);
 
@@ -113,7 +113,7 @@ pub fn compile_input(sess: Session,
         let expanded_crate = assign_node_ids(&sess, expanded_crate);
         // Lower ast -> hir.
         let foo = &42;
-        let lcx = LoweringContext::new(foo);
+        let lcx = LoweringContext::new(foo, &sess, &expanded_crate);
         let mut hir_forest = time(sess.time_passes(),
                                   "lowering ast -> hir",
                                   || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate)));
@@ -141,7 +141,7 @@ pub fn compile_input(sess: Session,
             lint::check_ast_crate(&sess, &expanded_crate)
         });
 
-        phase_3_run_analysis_passes(sess,
+        phase_3_run_analysis_passes(&sess,
                                     ast_map,
                                     &arenas,
                                     id,
@@ -282,7 +282,7 @@ pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> {
     pub ast_map: Option<&'a hir_map::Map<'ast>>,
     pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<&'a ty::ctxt<'tcx>>,
-    pub lcx: Option<&'a LoweringContext<'tcx>>,
+    pub lcx: Option<&'a LoweringContext<'a, 'tcx>>,
     pub trans: Option<&'a trans::CrateTranslation>,
 }
 
@@ -340,7 +340,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
                               krate: &'a ast::Crate,
                               hir_crate: &'a hir::Crate,
                               crate_name: &'a str,
-                              lcx: &'a LoweringContext<'tcx>)
+                              lcx: &'a LoweringContext<'a, 'tcx>)
                               -> CompileState<'a, 'ast, 'tcx> {
         CompileState {
             crate_name: Some(crate_name),
@@ -359,7 +359,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
                             hir_crate: &'a hir::Crate,
                             analysis: &'a ty::CrateAnalysis,
                             tcx: &'a ty::ctxt<'tcx>,
-                            lcx: &'a LoweringContext<'tcx>)
+                            lcx: &'a LoweringContext<'a, 'tcx>)
                             -> CompileState<'a, 'ast, 'tcx> {
         CompileState {
             analysis: Some(analysis),
@@ -659,13 +659,13 @@ pub fn make_map<'ast>(sess: &Session,
 /// Run the resolution, typechecking, region checking and other
 /// miscellaneous analysis passes on the crate. Return various
 /// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                ast_map: front::map::Map<'tcx>,
                                                arenas: &'tcx ty::CtxtArenas<'tcx>,
                                                name: String,
                                                make_glob_map: resolve::MakeGlobMap,
                                                f: F)
-                                               -> (Session, R)
+                                               -> R
                                                where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>,
                                                                        ty::CrateAnalysis) -> R
 {
@@ -673,7 +673,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
     let krate = ast_map.krate();
 
     time(time_passes, "external crate/lib resolution", ||
-         LocalCrateReader::new(&sess, &ast_map).read_crates(krate));
+         LocalCrateReader::new(sess, &ast_map).read_crates(krate));
 
     let lang_items = time(time_passes, "language item collection", ||
                           middle::lang_items::collect_language_items(&sess, &ast_map));
@@ -687,7 +687,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
         glob_map,
     } =
         time(time_passes, "resolution",
-             || resolve::resolve_crate(&sess, &ast_map, make_glob_map));
+             || resolve::resolve_crate(sess, &ast_map, make_glob_map));
 
     // Discard MTWT tables that aren't required past resolution.
     if !sess.opts.debugging_opts.keep_mtwt_tables {
@@ -695,10 +695,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
     }
 
     let named_region_map = time(time_passes, "lifetime resolution",
-                                || middle::resolve_lifetime::krate(&sess, krate, &def_map));
+                                || middle::resolve_lifetime::krate(sess, krate, &def_map));
 
     time(time_passes, "looking for entry point",
-         || middle::entry::find_entry_point(&sess, &ast_map));
+         || middle::entry::find_entry_point(sess, &ast_map));
 
     sess.plugin_registrar_fn.set(
         time(time_passes, "looking for plugin registrar", ||
@@ -706,13 +706,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
                 sess.diagnostic(), krate)));
 
     let region_map = time(time_passes, "region resolution", ||
-                          middle::region::resolve_crate(&sess, krate));
+                          middle::region::resolve_crate(sess, krate));
 
     time(time_passes, "loop checking", ||
-         middle::check_loop::check_crate(&sess, krate));
+         middle::check_loop::check_crate(sess, krate));
 
     time(time_passes, "static item recursion checking", ||
-         middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
+         middle::check_static_recursion::check_crate(sess, krate, &def_map, &ast_map));
 
     ty::ctxt::create_and_enter(sess,
                                arenas,
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 53b940c57a7..09a1d6f6851 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -131,7 +131,7 @@ pub fn parse_pretty(sess: &Session,
 impl PpSourceMode {
     /// Constructs a `PrinterSupport` object and passes it to `f`.
     fn call_with_pp_support<'tcx, A, B, F>(&self,
-                                           sess: Session,
+                                           sess: &'tcx Session,
                                            ast_map: Option<hir_map::Map<'tcx>>,
                                            payload: B,
                                            f: F) -> A where
@@ -155,7 +155,7 @@ impl PpSourceMode {
         }
     }
     fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
-                                               sess: Session,
+                                               sess: &'tcx Session,
                                                ast_map: &hir_map::Map<'tcx>,
                                                arenas: &'tcx ty::CtxtArenas<'tcx>,
                                                id: String,
@@ -185,7 +185,7 @@ impl PpSourceMode {
                                                     |tcx, _| {
                     let annotation = TypedAnnotation { tcx: tcx };
                     f(&annotation, payload, &ast_map.forest.krate)
-                }).1
+                })
             }
             _ => panic!("Should use call_with_pp_support"),
         }
@@ -224,13 +224,13 @@ trait HirPrinterSupport<'ast>: pprust_hir::PpAnn {
     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn;
 }
 
-struct NoAnn<'ast> {
-    sess: Session,
+struct NoAnn<'ast, 'tcx> {
+    sess: &'tcx Session,
     ast_map: Option<hir_map::Map<'ast>>
 }
 
-impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
-    fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+impl<'ast, 'tcx> PrinterSupport<'ast> for NoAnn<'ast, 'tcx> {
+    fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
         self.ast_map.as_ref()
@@ -239,8 +239,8 @@ impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
-    fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+impl<'ast, 'tcx> HirPrinterSupport<'ast> for NoAnn<'ast, 'tcx> {
+    fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
         self.ast_map.as_ref()
@@ -249,16 +249,16 @@ impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { self }
 }
 
-impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
-impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
+impl<'ast, 'tcx> pprust::PpAnn for NoAnn<'ast, 'tcx> {}
+impl<'ast, 'tcx> pprust_hir::PpAnn for NoAnn<'ast, 'tcx> {}
 
-struct IdentifiedAnnotation<'ast> {
-    sess: Session,
+struct IdentifiedAnnotation<'ast, 'tcx> {
+    sess: &'tcx Session,
     ast_map: Option<hir_map::Map<'ast>>,
 }
 
-impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
-    fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+impl<'ast, 'tcx> PrinterSupport<'ast> for IdentifiedAnnotation<'ast, 'tcx> {
+    fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
         self.ast_map.as_ref()
@@ -267,7 +267,7 @@ impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> {
+impl<'ast, 'tcx> pprust::PpAnn for IdentifiedAnnotation<'ast, 'tcx> {
     fn pre(&self,
            s: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
@@ -307,8 +307,8 @@ impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> {
     }
 }
 
-impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
-    fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+impl<'ast, 'tcx> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast, 'tcx> {
+    fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
         self.ast_map.as_ref()
@@ -317,7 +317,7 @@ impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { self }
 }
 
-impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
+impl<'ast, 'tcx> pprust_hir::PpAnn for IdentifiedAnnotation<'ast, 'tcx> {
     fn pre(&self,
            s: &mut pprust_hir::State,
            node: pprust_hir::AnnNode) -> io::Result<()> {
@@ -356,13 +356,13 @@ impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
     }
 }
 
-struct HygieneAnnotation<'ast> {
-    sess: Session,
+struct HygieneAnnotation<'ast, 'tcx> {
+    sess: &'tcx Session,
     ast_map: Option<hir_map::Map<'ast>>,
 }
 
-impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> {
-    fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+impl<'ast, 'tcx> PrinterSupport<'ast> for HygieneAnnotation<'ast, 'tcx> {
+    fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
         self.ast_map.as_ref()
@@ -371,7 +371,7 @@ impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> {
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
+impl<'ast, 'tcx> pprust::PpAnn for HygieneAnnotation<'ast, 'tcx> {
     fn post(&self,
             s: &mut pprust::State,
             node: pprust::AnnNode) -> io::Result<()> {
@@ -671,7 +671,7 @@ pub fn pretty_print_input(sess: Session,
     // the ordering of stuff super-finicky.
     let mut hir_forest;
     let foo = &42;
-    let lcx = LoweringContext::new(foo);
+    let lcx = LoweringContext::new(foo, &sess, &krate);
     let arenas = ty::CtxtArenas::new();
     let ast_map = if compute_ast_map {
         hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate));
@@ -697,7 +697,7 @@ pub fn pretty_print_input(sess: Session,
             // Silently ignores an identified node.
             let out: &mut Write = &mut out;
             s.call_with_pp_support(
-                sess, ast_map, box out, |annotation, out| {
+                &sess, ast_map, box out, |annotation, out| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     pprust::print_crate(sess.codemap(),
@@ -714,7 +714,7 @@ pub fn pretty_print_input(sess: Session,
         (PpmHir(s), None) => {
             let out: &mut Write = &mut out;
             s.call_with_pp_support_hir(
-                sess, &ast_map.unwrap(), &arenas, id, box out, |annotation, out, krate| {
+                &sess, &ast_map.unwrap(), &arenas, id, box out, |annotation, out, krate| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     pprust_hir::print_crate(sess.codemap(),
@@ -730,7 +730,7 @@ pub fn pretty_print_input(sess: Session,
 
         (PpmHir(s), Some(uii)) => {
             let out: &mut Write = &mut out;
-            s.call_with_pp_support_hir(sess,
+            s.call_with_pp_support_hir(&sess,
                                        &ast_map.unwrap(),
                                        &arenas,
                                        id,
@@ -778,14 +778,14 @@ pub fn pretty_print_input(sess: Session,
             match code {
                 Some(code) => {
                     let variants = gather_flowgraph_variants(&sess);
-                    driver::phase_3_run_analysis_passes(sess,
+                    driver::phase_3_run_analysis_passes(&sess,
                                                         ast_map,
                                                         &arenas,
                                                         id,
                                                         resolve::MakeGlobMap::No,
                                                         |tcx, _| {
                         print_flowgraph(variants, tcx, code, mode, out)
-                    }).1
+                    })
                 }
                 None => {
                     let message = format!("--pretty=flowgraph needs \
diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs
index c3544ff1aa0..c8f5f89b669 100644
--- a/src/librustc_front/lowering.rs
+++ b/src/librustc_front/lowering.rs
@@ -14,20 +14,38 @@ use hir;
 
 use syntax::ast::*;
 use syntax::ptr::P;
-use syntax::codemap::{respan, Spanned};
+use syntax::codemap::{respan, Spanned, Span};
 use syntax::owned_slice::OwnedSlice;
+use syntax::parse::token::{self, str_to_ident};
+use syntax::std_inject;
 
-pub struct LoweringContext<'hir> {
+pub struct LoweringContext<'a, 'hir> {
     // TODO
     foo: &'hir i32,
+    id_assigner: &'a NodeIdAssigner,
+    crate_root: Option<&'static str>,
 }
 
-impl<'hir> LoweringContext<'hir> {
-    pub fn new(foo: &'hir i32) -> LoweringContext<'hir> {
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+    pub fn new(foo: &'hir i32, id_assigner: &'a NodeIdAssigner, c: &Crate) -> LoweringContext<'a, 'hir> {
+        let crate_root = if std_inject::no_core(c) {
+            None
+        } else if std_inject::no_std(c) {
+            Some("core")
+        } else {
+            Some("std")
+        };
+
         LoweringContext {
             foo: foo,
+            id_assigner: id_assigner,
+            crate_root: crate_root,
         }
     }
+
+    fn next_id(&self) -> NodeId {
+        self.id_assigner.next_node_id()
+    }
 }
 
 pub fn lower_view_path(_lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
@@ -727,105 +745,105 @@ pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
     })
 }
 
-pub fn lower_expr(_lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
+pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
     P(hir::Expr {
             id: e.id,
             node: match e.node {
                 ExprBox(ref e) => {
-                    hir::ExprBox(lower_expr(_lctx, e))
+                    hir::ExprBox(lower_expr(lctx, e))
                 }
                 ExprVec(ref exprs) => {
-                    hir::ExprVec(exprs.iter().map(|x| lower_expr(_lctx, x)).collect())
+                    hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect())
                 }
                 ExprRepeat(ref expr, ref count) => {
-                    hir::ExprRepeat(lower_expr(_lctx, expr), lower_expr(_lctx, count))
+                    hir::ExprRepeat(lower_expr(lctx, expr), lower_expr(lctx, count))
                 }
                 ExprTup(ref elts) => {
-                    hir::ExprTup(elts.iter().map(|x| lower_expr(_lctx, x)).collect())
+                    hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect())
                 }
                 ExprCall(ref f, ref args) => {
-                    hir::ExprCall(lower_expr(_lctx, f),
-                             args.iter().map(|x| lower_expr(_lctx, x)).collect())
+                    hir::ExprCall(lower_expr(lctx, f),
+                             args.iter().map(|x| lower_expr(lctx, x)).collect())
                 }
                 ExprMethodCall(i, ref tps, ref args) => {
                     hir::ExprMethodCall(
                         respan(i.span, i.node.name),
-                        tps.iter().map(|x| lower_ty(_lctx, x)).collect(),
-                        args.iter().map(|x| lower_expr(_lctx, x)).collect())
+                        tps.iter().map(|x| lower_ty(lctx, x)).collect(),
+                        args.iter().map(|x| lower_expr(lctx, x)).collect())
                 }
                 ExprBinary(binop, ref lhs, ref rhs) => {
-                    hir::ExprBinary(lower_binop(_lctx, binop),
-                            lower_expr(_lctx, lhs),
-                            lower_expr(_lctx, rhs))
+                    hir::ExprBinary(lower_binop(lctx, binop),
+                            lower_expr(lctx, lhs),
+                            lower_expr(lctx, rhs))
                 }
                 ExprUnary(op, ref ohs) => {
-                    hir::ExprUnary(lower_unop(_lctx, op), lower_expr(_lctx, ohs))
+                    hir::ExprUnary(lower_unop(lctx, op), lower_expr(lctx, ohs))
                 }
                 ExprLit(ref l) => hir::ExprLit(P((**l).clone())),
                 ExprCast(ref expr, ref ty) => {
-                    hir::ExprCast(lower_expr(_lctx, expr), lower_ty(_lctx, ty))
+                    hir::ExprCast(lower_expr(lctx, expr), lower_ty(lctx, ty))
                 }
                 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) => {
-                    hir::ExprIf(lower_expr(_lctx, cond),
-                           lower_block(_lctx, tr),
-                           fl.as_ref().map(|x| lower_expr(_lctx, x)))
+                    hir::ExprIf(lower_expr(lctx, cond),
+                           lower_block(lctx, tr),
+                           fl.as_ref().map(|x| lower_expr(lctx, x)))
                 }
                 ExprWhile(ref cond, ref body, opt_ident) => {
-                    hir::ExprWhile(lower_expr(_lctx, cond),
-                              lower_block(_lctx, body),
+                    hir::ExprWhile(lower_expr(lctx, cond),
+                              lower_block(lctx, body),
                               opt_ident)
                 }
                 ExprLoop(ref body, opt_ident) => {
-                    hir::ExprLoop(lower_block(_lctx, body),
+                    hir::ExprLoop(lower_block(lctx, body),
                             opt_ident)
                 }
                 ExprMatch(ref expr, ref arms, ref source) => {
-                    hir::ExprMatch(lower_expr(_lctx, expr),
-                            arms.iter().map(|x| lower_arm(_lctx, x)).collect(),
-                            lower_match_source(_lctx, source))
+                    hir::ExprMatch(lower_expr(lctx, expr),
+                            arms.iter().map(|x| lower_arm(lctx, x)).collect(),
+                            lower_match_source(lctx, source))
                 }
                 ExprClosure(capture_clause, ref decl, ref body) => {
-                    hir::ExprClosure(lower_capture_clause(_lctx, capture_clause),
-                                lower_fn_decl(_lctx, decl),
-                                lower_block(_lctx, body))
+                    hir::ExprClosure(lower_capture_clause(lctx, capture_clause),
+                                lower_fn_decl(lctx, decl),
+                                lower_block(lctx, body))
                 }
-                ExprBlock(ref blk) => hir::ExprBlock(lower_block(_lctx, blk)),
+                ExprBlock(ref blk) => hir::ExprBlock(lower_block(lctx, blk)),
                 ExprAssign(ref el, ref er) => {
-                    hir::ExprAssign(lower_expr(_lctx, el), lower_expr(_lctx, er))
+                    hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er))
                 }
                 ExprAssignOp(op, ref el, ref er) => {
-                    hir::ExprAssignOp(lower_binop(_lctx, op),
-                                lower_expr(_lctx, el),
-                                lower_expr(_lctx, er))
+                    hir::ExprAssignOp(lower_binop(lctx, op),
+                                lower_expr(lctx, el),
+                                lower_expr(lctx, er))
                 }
                 ExprField(ref el, ident) => {
-                    hir::ExprField(lower_expr(_lctx, el), respan(ident.span, ident.node.name))
+                    hir::ExprField(lower_expr(lctx, el), respan(ident.span, ident.node.name))
                 }
                 ExprTupField(ref el, ident) => {
-                    hir::ExprTupField(lower_expr(_lctx, el), ident)
+                    hir::ExprTupField(lower_expr(lctx, el), ident)
                 }
                 ExprIndex(ref el, ref er) => {
-                    hir::ExprIndex(lower_expr(_lctx, el), lower_expr(_lctx, er))
+                    hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er))
                 }
                 ExprRange(ref e1, ref e2) => {
-                    hir::ExprRange(e1.as_ref().map(|x| lower_expr(_lctx, x)),
-                              e2.as_ref().map(|x| lower_expr(_lctx, x)))
+                    hir::ExprRange(e1.as_ref().map(|x| lower_expr(lctx, x)),
+                              e2.as_ref().map(|x| lower_expr(lctx, x)))
                 }
                 ExprPath(ref qself, ref path) => {
                     let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
                         hir::QSelf {
-                            ty: lower_ty(_lctx, ty),
+                            ty: lower_ty(lctx, ty),
                             position: position
                         }
                     });
-                    hir::ExprPath(qself, lower_path(_lctx, path))
+                    hir::ExprPath(qself, lower_path(lctx, path))
                 }
                 ExprBreak(opt_ident) => hir::ExprBreak(opt_ident),
                 ExprAgain(opt_ident) => hir::ExprAgain(opt_ident),
-                ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(_lctx, x))),
+                ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))),
                 ExprInlineAsm(InlineAsm {
                     ref inputs,
                     ref outputs,
@@ -838,10 +856,10 @@ pub fn lower_expr(_lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                     expn_id,
                 }) => hir::ExprInlineAsm(hir::InlineAsm {
                     inputs: inputs.iter().map(|&(ref c, ref input)| {
-                        (c.clone(), lower_expr(_lctx, input))
+                        (c.clone(), lower_expr(lctx, input))
                     }).collect(),
                     outputs: outputs.iter().map(|&(ref c, ref out, ref is_rw)| {
-                        (c.clone(), lower_expr(_lctx, out), *is_rw)
+                        (c.clone(), lower_expr(lctx, out), *is_rw)
                     }).collect(),
                     asm: asm.clone(),
                     asm_str_style: asm_str_style,
@@ -852,17 +870,124 @@ pub fn lower_expr(_lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                     expn_id: expn_id,
                 }),
                 ExprStruct(ref path, ref fields, ref maybe_expr) => {
-                    hir::ExprStruct(lower_path(_lctx, path),
-                            fields.iter().map(|x| lower_field(_lctx, x)).collect(),
-                            maybe_expr.as_ref().map(|x| lower_expr(_lctx, x)))
+                    hir::ExprStruct(lower_path(lctx, path),
+                            fields.iter().map(|x| lower_field(lctx, x)).collect(),
+                            maybe_expr.as_ref().map(|x| lower_expr(lctx, x)))
                 },
                 ExprParen(ref ex) => {
-                    return lower_expr(_lctx, ex);
+                    return lower_expr(lctx, ex);
+                }
+                ExprInPlace(..) => {
+                    panic!("todo");
+                }
+                ExprIfLet(..) => {
+                    panic!("todo");
+                }
+                ExprWhileLet(..) => {
+                    panic!("todo");
+                }
+
+                // Desugar ExprForLoop
+                // From: `[opt_ident]: for <pat> in <head> <body>`
+                ExprForLoop(ref pat, ref head, ref body, ref opt_ident) => {
+                    // to:
+                    //
+                    //   {
+                    //     let result = 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
+                    //           }
+                    //         }
+                    //       }
+                    //     };
+                    //     result
+                    //   }
+
+                    // expand <head>
+                    let head = lower_expr(lctx, head);
+
+                    let iter = token::gensym_ident("iter");
+
+                    // `::std::option::Option::Some(<pat>) => <body>`
+                    let pat_arm = {
+                        let body_block = lower_block(lctx, body);
+                        let body_span = body_block.span;
+                        let body_expr = P(hir::Expr {
+                            id: lctx.next_id(),
+                            node: hir::ExprBlock(body_block),
+                            span: body_span,
+                        });
+                        let pat = lower_pat(lctx, pat);
+                        let some_pat = pat_some(lctx, e.span, pat);
+
+                        arm(vec![some_pat], body_expr)
+                    };
+
+                    // `::std::option::Option::None => break`
+                    let break_arm = {
+                        let break_expr = expr_break(lctx, e.span);
+
+                        arm(vec![pat_none(lctx, e.span)], break_expr)
+                    };
+
+                    // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+                    let match_expr = {
+                        let next_path = {
+                            let strs = std_path(lctx, &["iter", "Iterator", "next"]);
+
+                            path_global(e.span, strs)
+                        };
+                        let ref_mut_iter = expr_mut_addr_of(lctx, e.span, expr_ident(lctx, e.span, iter));
+                        let next_expr =
+                            expr_call(lctx, e.span, expr_path(lctx, next_path), vec![ref_mut_iter]);
+                        let arms = vec![pat_arm, break_arm];
+
+                        expr(lctx,
+                             e.span,
+                             hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar))
+                    };
+
+                    // `[opt_ident]: loop { ... }`
+                    let loop_block = block_expr(lctx, match_expr);
+                    let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident.clone()));
+
+                    // `mut iter => { ... }`
+                    let iter_arm = {
+                        let iter_pat =
+                            pat_ident_binding_mode(lctx, e.span, iter, hir::BindByValue(hir::MutMutable));
+                        arm(vec![iter_pat], loop_expr)
+                    };
+
+                    // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
+                    let into_iter_expr = {
+                        let into_iter_path = {
+                            let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]);
+
+                            path_global(e.span, strs)
+                        };
+
+                        expr_call(lctx, e.span, expr_path(lctx, into_iter_path), vec![head])
+                    };
+
+                    let match_expr = expr_match(lctx, e.span, into_iter_expr, vec![iter_arm]);
+
+                    // `{ let result = ...; result }`
+                    let result_ident = token::gensym_ident("result");
+                    let result = expr_block(lctx,
+                                            block_all(lctx,
+                                                      e.span,
+                                                      vec![stmt_let(lctx,
+                                                                    e.span,
+                                                                    false,
+                                                                    result_ident,
+                                                                    match_expr)],
+                                                      Some(expr_ident(lctx, e.span, result_ident))));
+                    return result;
                 }
-                ExprInPlace(..) |
-                ExprIfLet(..) |
-                ExprWhileLet(..) |
-                ExprForLoop(..) |
+
                 ExprMac(_) => panic!("Shouldn't exist here"),
             },
             span: e.span,
@@ -972,3 +1097,168 @@ pub fn lower_trait_bound_modifier(_lctx: &LoweringContext,
         TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
     }
 }
+
+// Helper methods for building HIR.
+
+fn arm(pats: Vec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
+    hir::Arm {
+        attrs: vec!(),
+        pats: pats,
+        guard: None,
+        body: expr
+    }
+}
+
+fn expr_break(lctx: &LoweringContext, span: Span) -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprBreak(None))
+}
+
+fn expr_call(lctx: &LoweringContext, span: Span, e: P<hir::Expr>, args: Vec<P<hir::Expr>>) -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprCall(e, args))
+}
+
+fn expr_ident(lctx: &LoweringContext, span: Span, id: Ident) -> P<hir::Expr> {
+    expr_path(lctx, path_ident(span, id))
+}
+
+fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P<hir::Expr>) -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e))
+}
+
+fn expr_path(lctx: &LoweringContext, path: hir::Path) -> P<hir::Expr> {
+    expr(lctx, path.span, hir::ExprPath(None, path))
+}
+
+fn expr_match(lctx: &LoweringContext, span: Span, arg: P<hir::Expr>, arms: Vec<hir::Arm>) -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprMatch(arg, arms, hir::MatchSource::Normal))
+}
+
+fn expr_block(lctx: &LoweringContext, b: P<hir::Block>) -> P<hir::Expr> {
+    expr(lctx, b.span, hir::ExprBlock(b))
+}
+
+fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_) -> P<hir::Expr> {
+    P(hir::Expr {
+        id: lctx.next_id(),
+        node: node,
+        span: span,
+    })
+}
+
+fn stmt_let(lctx: &LoweringContext, sp: Span, mutbl: bool, ident: Ident, ex: P<hir::Expr>) -> P<hir::Stmt> {
+    let pat = if mutbl {
+        pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable))
+    } else {
+        pat_ident(lctx, sp, ident)
+    };
+    let local = P(hir::Local {
+        pat: pat,
+        ty: None,
+        init: Some(ex),
+        id: lctx.next_id(),
+        span: sp,
+    });
+    let decl = respan(sp, hir::DeclLocal(local));
+    P(respan(sp, hir::StmtDecl(P(decl), lctx.next_id())))
+}
+
+fn block_expr(lctx: &LoweringContext, expr: P<hir::Expr>) -> P<hir::Block> {
+    block_all(lctx, expr.span, Vec::new(), Some(expr))
+}
+
+fn block_all(lctx: &LoweringContext,
+             span: Span,
+             stmts: Vec<P<hir::Stmt>>,
+             expr: Option<P<hir::Expr>>) -> P<hir::Block> {
+        P(hir::Block {
+            stmts: stmts,
+            expr: expr,
+            id: lctx.next_id(),
+            rules: hir::DefaultBlock,
+            span: span,
+        })
+}
+
+fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+    let some = std_path(lctx, &["option", "Option", "Some"]);
+    let path = path_global(span, some);
+    pat_enum(lctx, span, path, vec!(pat))
+}
+
+fn pat_none(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
+    let none = std_path(lctx, &["option", "Option", "None"]);
+    let path = path_global(span, none);
+    pat_enum(lctx, span, path, vec![])
+}
+
+fn pat_enum(lctx: &LoweringContext, span: Span, path: hir::Path, subpats: Vec<P<hir::Pat>>) -> P<hir::Pat> {
+    let pt = hir::PatEnum(path, Some(subpats));
+    pat(lctx, span, pt)
+}
+
+fn pat_ident(lctx: &LoweringContext, span: Span, ident: Ident) -> P<hir::Pat> {
+    pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable))
+}
+
+fn pat_ident_binding_mode(lctx: &LoweringContext,
+                          span: Span,
+                          ident: Ident,
+                          bm: hir::BindingMode) -> P<hir::Pat> {
+    let pat_ident = hir::PatIdent(bm, Spanned{span: span, node: ident}, None);
+    pat(lctx, span, pat_ident)
+}
+
+fn pat(lctx: &LoweringContext, span: Span, pat: hir::Pat_) -> P<hir::Pat> {
+    P(hir::Pat { id: lctx.next_id(), node: pat, span: span })
+}
+
+fn path_ident(span: Span, id: Ident) -> hir::Path {
+    path(span, vec!(id))
+}
+
+fn path(span: Span, strs: Vec<Ident> ) -> hir::Path {
+    path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new())
+}
+
+fn path_global(span: Span, strs: Vec<Ident> ) -> hir::Path {
+    path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new())
+}
+
+fn path_all(sp: Span,
+            global: bool,
+            mut idents: Vec<Ident> ,
+            lifetimes: Vec<hir::Lifetime>,
+            types: Vec<P<hir::Ty>>,
+            bindings: Vec<P<hir::TypeBinding>> )
+            -> hir::Path {
+    let last_identifier = idents.pop().unwrap();
+    let mut segments: Vec<hir::PathSegment> = idents.into_iter()
+                                                    .map(|ident| {
+        hir::PathSegment {
+            identifier: ident,
+            parameters: hir::PathParameters::none(),
+        }
+    }).collect();
+    segments.push(hir::PathSegment {
+        identifier: last_identifier,
+        parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
+            lifetimes: lifetimes,
+            types: OwnedSlice::from_vec(types),
+            bindings: OwnedSlice::from_vec(bindings),
+        })
+    });
+    hir::Path {
+        span: sp,
+        global: global,
+        segments: segments,
+    }
+}
+
+fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec<Ident> {
+    let mut v = Vec::new();
+    if let Some(s) = lctx.crate_root {
+        v.push(str_to_ident(s));
+    }
+    v.extend(components.iter().map(|s| str_to_ident(s)));
+    return v
+}
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 296dd44a9bc..6a6d0b3bdca 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -76,7 +76,7 @@ pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
 
 impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
     pub fn new(tcx: &'l ty::ctxt<'tcx>,
-               lcx: &'l LoweringContext<'tcx>,
+               lcx: &'l LoweringContext<'l, 'tcx>,
                analysis: &'l ty::CrateAnalysis,
                output_file: Box<File>)
                -> DumpCsvVisitor<'l, 'tcx> {
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 0d4d97d2b6a..5e26322ebda 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -38,7 +38,7 @@ mod dump_csv;
 
 pub struct SaveContext<'l, 'tcx: 'l> {
     tcx: &'l ty::ctxt<'tcx>,
-    lcx: &'l lowering::LoweringContext<'tcx>,
+    lcx: &'l lowering::LoweringContext<'l, 'tcx>,
     span_utils: SpanUtils<'l>,
 }
 
@@ -177,13 +177,15 @@ pub struct MethodCallData {
 
 
 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
-    pub fn new(tcx: &'l ty::ctxt<'tcx>, lcx: &'l lowering::LoweringContext<'tcx>) -> SaveContext<'l, 'tcx> {
+    pub fn new(tcx: &'l ty::ctxt<'tcx>,
+               lcx: &'l lowering::LoweringContext<'l, 'tcx>)
+               -> SaveContext<'l, 'tcx> {
         let span_utils = SpanUtils::new(&tcx.sess);
         SaveContext::from_span_utils(tcx, lcx, span_utils)
     }
 
     pub fn from_span_utils(tcx: &'l ty::ctxt<'tcx>,
-                           lcx: &'l lowering::LoweringContext<'tcx>,
+                           lcx: &'l lowering::LoweringContext<'l, 'tcx>,
                            span_utils: SpanUtils<'l>)
                            -> SaveContext<'l, 'tcx> {
         SaveContext {
@@ -709,7 +711,7 @@ impl<'v> Visitor<'v> for PathCollector {
 }
 
 pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>,
-                               lcx: &'l lowering::LoweringContext<'tcx>,
+                               lcx: &'l lowering::LoweringContext<'l, 'tcx>,
                                krate: &ast::Crate,
                                analysis: &ty::CrateAnalysis,
                                odir: Option<&Path>) {
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index b3ec10a8941..5afcdbc8c13 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -38,6 +38,7 @@ use std::cell::RefCell;
 use std::rc::Rc;
 use syntax::codemap::Span;
 use syntax::parse::token;
+use syntax::ast::NodeIdAssigner;
 use util::nodemap::{DefIdMap, FnvHashMap};
 use rustc::front::map as hir_map;
 use rustc::front::map::NodeItem;
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ce00505b0b4..bf43b87b267 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -375,6 +375,10 @@ pub const CRATE_NODE_ID: NodeId = 0;
 /// small, positive ids.
 pub const DUMMY_NODE_ID: NodeId = !0;
 
+pub trait NodeIdAssigner {
+    fn next_node_id(&self) -> NodeId;
+}
+
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
 /// the "special" built-in traits (see middle::lang_items) and
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b15c51490a1..8cfad6341de 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -360,102 +360,10 @@ 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) => {
-            // to:
-            //
-            //   {
-            //     let result = 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
-            //           }
-            //         }
-            //       }
-            //     };
-            //     result
-            //   }
-
-            push_compiler_expansion(fld, span, CompilerExpansionFormat::ForLoop);
-
-            let span = fld.new_span(span);
-
-            // expand <head>
             let head = fld.fold_expr(head);
-
-            let iter = token::gensym_ident("iter");
-
-            let pat_span = fld.new_span(pat.span);
-            // `::std::option::Option::Some(<pat>) => <body>`
-            let pat_arm = {
-                let body_expr = fld.cx.expr_block(body);
-                let pat = fld.fold_pat(pat);
-                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 = fld.cx.std_path(&["iter", "Iterator", "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];
-
-                fld.cx.expr(pat_span,
-                            ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar))
-            };
-
-            // `[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 = fld.cx.std_path(&["iter", "IntoIterator",
-                                                 "into_iter"]);
-
-                    fld.cx.path_global(span, strs)
-                };
-
-                fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
-            };
-
-            let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]);
-
-            // `{ let result = ...; result }`
-            let result_ident = token::gensym_ident("result");
-            let result = fld.cx.expr_block(
-                fld.cx.block_all(
-                    span,
-                    vec![fld.cx.stmt_let(span, false, result_ident, match_expr)],
-                    Some(fld.cx.expr_ident(span, result_ident))));
-            fld.cx.bt_pop();
-            result
+            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
+            fld.cx.expr(span, ast::ExprForLoop(pat, head, body, opt_ident))
         }
 
         ast::ExprClosure(capture_clause, fn_decl, block) => {