about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-04-15 17:11:24 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-05-07 07:14:54 +0300
commitcde2f5f11639edb2f943b6caa5f3b930c0c4f214 (patch)
tree4418cb00a2f3ec654be13b58aa63c0e6a6b9af11
parentbbc41aa9a674b80c4423ca6196fb334fd4d17776 (diff)
downloadrust-cde2f5f11639edb2f943b6caa5f3b930c0c4f214.tar.gz
rust-cde2f5f11639edb2f943b6caa5f3b930c0c4f214.zip
mir: factor out the parts of MIR building which are not fn-specific.
-rw-r--r--src/librustc_mir/build/mod.rs228
-rw-r--r--src/librustc_mir/mir_map.rs110
2 files changed, 157 insertions, 181 deletions
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 1ed5fabf274..004a2aada6a 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -10,12 +10,13 @@
 
 use hair::cx::Cx;
 use rustc::middle::region::{CodeExtent, CodeExtentData};
-use rustc::ty::{self, FnOutput, Ty};
+use rustc::ty::{self, Ty};
 use rustc::mir::repr::*;
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc::hir;
 use rustc::hir::pat_util::pat_is_binding;
 use std::ops::{Index, IndexMut};
+use syntax::abi::Abi;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::parse::token::keywords;
@@ -159,53 +160,31 @@ macro_rules! unpack {
 ///////////////////////////////////////////////////////////////////////////
 /// the main entry point for building MIR for a function
 
-pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
-                          span: Span,
-                          fn_id: ast::NodeId,
-                          body_id: ast::NodeId,
-                          implicit_arguments: Vec<Ty<'tcx>>,
-                          explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
-                          return_ty: FnOutput<'tcx>,
-                          ast_block: &'tcx hir::Block)
-                          -> (Mir<'tcx>, ScopeAuxiliaryVec) {
+pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a,'tcx>,
+                                 fn_id: ast::NodeId,
+                                 arguments: A,
+                                 return_ty: ty::FnOutput<'tcx>,
+                                 ast_block: &'tcx hir::Block)
+                                 -> (Mir<'tcx>, ScopeAuxiliaryVec)
+    where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
+{
     let tcx = hir.tcx();
-    let cfg = CFG { basic_blocks: vec![] };
-
-    let mut builder = Builder {
-        hir: hir,
-        cfg: cfg,
-        fn_span: span,
-        scopes: vec![],
-        scope_datas: vec![],
-        scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
-        loop_scopes: vec![],
-        temp_decls: vec![],
-        var_decls: vec![],
-        var_indices: FnvHashMap(),
-        unit_temp: None,
-        cached_resume_block: None,
-        cached_return_block: None
-    };
-
-    assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
+    let span = tcx.map.span(fn_id);
+    let mut builder = Builder::new(hir, span);
 
-    let mut arg_decls = None; // assigned to `Some` in closures below
+    let body_id = ast_block.id;
     let call_site_extent =
         tcx.region_maps.lookup_code_extent(
             CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
-    let _ = builder.in_scope(call_site_extent, START_BLOCK, |builder, call_site_scope_id| {
-        let mut block = START_BLOCK;
-        let arg_extent =
-            tcx.region_maps.lookup_code_extent(
-                CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
-        unpack!(block = builder.in_scope(arg_extent, block, |builder, arg_scope_id| {
-            arg_decls = Some(unpack!(block = builder.args_and_body(block,
-                                                                   return_ty,
-                                                                   implicit_arguments,
-                                                                   explicit_arguments,
-                                                                   arg_scope_id,
-                                                                   ast_block)));
-            block.unit()
+    let arg_extent =
+        tcx.region_maps.lookup_code_extent(
+            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
+    let mut block = START_BLOCK;
+    let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block,
+                                                         |builder, call_site_scope_id| {
+        let arg_decls = unpack!(block = builder.in_scope(arg_extent, block,
+                                                         |builder, arg_scope_id| {
+            builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block)
         }));
 
         let return_block = builder.return_block();
@@ -213,20 +192,19 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
                               TerminatorKind::Goto { target: return_block });
         builder.cfg.terminate(return_block, call_site_scope_id, span,
                               TerminatorKind::Return);
-        return_block.unit()
-    });
-
-    assert!(
-        builder.cfg.basic_blocks
-                   .iter()
-                   .enumerate()
-                   .all(|(index, block)| {
-                       if block.terminator.is_none() {
-                           bug!("no terminator on block {:?} in fn {:?}",
-                                index, fn_id)
-                       }
-                       true
-                   }));
+        return_block.and(arg_decls)
+    }));
+    assert_eq!(block, builder.return_block());
+
+    match tcx.node_id_to_type(fn_id).sty {
+        ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
+            // RustCall pseudo-ABI untuples the last argument.
+            if let Some(arg_decl) = arg_decls.last_mut() {
+                arg_decl.spread = true;
+            }
+        }
+        _ => {}
+    }
 
     // Gather the upvars of a closure, if any.
     let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
@@ -251,72 +229,98 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
         }).collect()
     });
 
-    (
-        Mir {
-            basic_blocks: builder.cfg.basic_blocks,
-            scopes: builder.scope_datas,
-            var_decls: builder.var_decls,
-            arg_decls: arg_decls.take().expect("args never built?"),
-            temp_decls: builder.temp_decls,
-            upvar_decls: upvar_decls,
-            return_ty: return_ty,
-            span: span
-        },
-        builder.scope_auxiliary,
-    )
+    builder.finish(upvar_decls, arg_decls, return_ty)
 }
 
 impl<'a,'tcx> Builder<'a,'tcx> {
-    fn args_and_body(&mut self,
-                     mut block: BasicBlock,
-                     return_ty: FnOutput<'tcx>,
-                     implicit_arguments: Vec<Ty<'tcx>>,
-                     explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
-                     argument_scope_id: ScopeId,
-                     ast_block: &'tcx hir::Block)
-                     -> BlockAnd<Vec<ArgDecl<'tcx>>>
+    fn new(hir: Cx<'a, 'tcx>, span: Span) -> Builder<'a, 'tcx> {
+        let mut builder = Builder {
+            hir: hir,
+            cfg: CFG { basic_blocks: vec![] },
+            fn_span: span,
+            scopes: vec![],
+            scope_datas: vec![],
+            scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
+            loop_scopes: vec![],
+            temp_decls: vec![],
+            var_decls: vec![],
+            var_indices: FnvHashMap(),
+            unit_temp: None,
+            cached_resume_block: None,
+            cached_return_block: None
+        };
+
+        assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
+
+        builder
+    }
+
+    fn finish(self,
+              upvar_decls: Vec<UpvarDecl>,
+              arg_decls: Vec<ArgDecl<'tcx>>,
+              return_ty: ty::FnOutput<'tcx>)
+              -> (Mir<'tcx>, ScopeAuxiliaryVec) {
+        for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
+            if block.terminator.is_none() {
+                span_bug!(self.fn_span, "no terminator on block {:?}", index);
+            }
+        }
+
+        (Mir {
+            basic_blocks: self.cfg.basic_blocks,
+            scopes: self.scope_datas,
+            var_decls: self.var_decls,
+            arg_decls: arg_decls,
+            temp_decls: self.temp_decls,
+            upvar_decls: upvar_decls,
+            return_ty: return_ty,
+            span: self.fn_span
+        }, self.scope_auxiliary)
+    }
+
+    fn args_and_body<A>(&mut self,
+                        mut block: BasicBlock,
+                        return_ty: ty::FnOutput<'tcx>,
+                        arguments: A,
+                        argument_scope_id: ScopeId,
+                        ast_block: &'tcx hir::Block)
+                        -> BlockAnd<Vec<ArgDecl<'tcx>>>
+        where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
     {
         // to start, translate the argument patterns and collect the argument types.
-        let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
-        let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
-            let arg_decls =
-            implicits
-            .chain(explicits)
-            .enumerate()
-            .map(|(index, (ty, pattern))| {
-                let lvalue = Lvalue::Arg(index as u32);
-                if let Some(pattern) = pattern {
-                    let pattern = self.hir.irrefutable_pat(pattern);
-                    unpack!(block = self.lvalue_into_pattern(block,
-                                                             argument_scope_id,
-                                                             pattern,
-                                                             &lvalue));
-                }
+        let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
+            let lvalue = Lvalue::Arg(index as u32);
+            if let Some(pattern) = pattern {
+                let pattern = self.hir.irrefutable_pat(pattern);
+                unpack!(block = self.lvalue_into_pattern(block,
+                                                         argument_scope_id,
+                                                         pattern,
+                                                         &lvalue));
+            }
 
-                // Make sure we drop (parts of) the argument even when not matched on.
-                let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
-                self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
-                                   argument_extent, &lvalue, ty);
-
-                let mut name = keywords::Invalid.name();
-                if let Some(pat) = pattern {
-                    if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
-                        if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
-                            name = ident.node.name;
-                        }
+            // Make sure we drop (parts of) the argument even when not matched on.
+            let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
+            self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
+                               argument_extent, &lvalue, ty);
+
+            let mut name = keywords::Invalid.name();
+            if let Some(pat) = pattern {
+                if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
+                    if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
+                        name = ident.node.name;
                     }
                 }
+            }
 
-                ArgDecl {
-                    ty: ty,
-                    spread: false,
-                    debug_name: name
-                }
-            })
-            .collect();
+            ArgDecl {
+                ty: ty,
+                spread: false,
+                debug_name: name
+            }
+        }).collect();
 
         // FIXME(#32959): temporary hack for the issue at hand
-        let return_is_unit = if let FnOutput::FnConverging(t) = return_ty {
+        let return_is_unit = if let ty::FnConverging(t) = return_ty {
             t.is_nil()
         } else {
             false
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 97daa64994d..dad1f157288 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -28,11 +28,9 @@ use rustc::mir::mir_map::MirMap;
 use rustc::infer;
 use rustc::traits::ProjectionMode;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeMap;
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor};
-use syntax::abi::Abi;
 use syntax::ast;
 use syntax::codemap::Span;
 
@@ -58,6 +56,24 @@ struct BuildMir<'a, 'tcx: 'a> {
     map: &'a mut MirMap<'tcx>,
 }
 
+impl<'a, 'tcx> BuildMir<'a, 'tcx> {
+    fn build<F>(&mut self, id: ast::NodeId, f: F)
+        where F: for<'b> FnOnce(Cx<'b, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
+    {
+        let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
+        let infcx = infer::new_infer_ctxt(self.tcx,
+                                          &self.tcx.tables,
+                                          Some(param_env),
+                                          ProjectionMode::AnyFinal);
+
+        let (mir, scope_auxiliary) = f(Cx::new(&infcx));
+
+        pretty::dump_mir(self.tcx, "mir_map", &0, id, &mir, Some(&scope_auxiliary));
+
+        assert!(self.map.map.insert(id, mir).is_none())
+    }
+}
+
 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: intravisit::FnKind<'tcx>,
@@ -65,82 +81,38 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                 body: &'tcx hir::Block,
                 span: Span,
                 id: ast::NodeId) {
-        let implicit_arg_tys = if let intravisit::FnKind::Closure(..) = fk {
-            vec![closure_self_ty(&self.tcx, id, body.id)]
+        // fetch the fully liberated fn signature (that is, all bound
+        // types/lifetimes replaced)
+        let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) {
+            Some(f) => f.clone(),
+            None => {
+                span_bug!(span, "no liberated fn sig for {:?}", id);
+            }
+        };
+
+        let implicit_argument = if let intravisit::FnKind::Closure(..) = fk {
+            Some((closure_self_ty(&self.tcx, id, body.id), None))
         } else {
-            vec![]
+            None
         };
 
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
-        let infcx = infer::new_infer_ctxt(self.tcx,
-                                          &self.tcx.tables,
-                                          Some(param_env),
-                                          ProjectionMode::AnyFinal);
+        let explicit_arguments =
+            decl.inputs
+                .iter()
+                .enumerate()
+                .map(|(index, arg)| {
+                    (fn_sig.inputs[index], Some(&*arg.pat))
+                });
 
-        match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
-            Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
-            Err(ErrorReported) => {}
-        }
+        self.build(id, |cx| {
+            let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+            build::construct_fn(cx, id, arguments, fn_sig.output, body)
+        });
 
         intravisit::walk_fn(self, fk, decl, body, span);
     }
 }
 
-fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
-                         implicit_arg_tys: Vec<Ty<'tcx>>,
-                         fn_id: ast::NodeId,
-                         span: Span,
-                         decl: &'tcx hir::FnDecl,
-                         body: &'tcx hir::Block)
-                         -> Result<Mir<'tcx>, ErrorReported> {
-    // fetch the fully liberated fn signature (that is, all bound
-    // types/lifetimes replaced)
-    let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
-        Some(f) => f.clone(),
-        None => {
-            span_bug!(span, "no liberated fn sig for {:?}", fn_id);
-        }
-    };
-
-    let arguments =
-        decl.inputs
-            .iter()
-            .enumerate()
-            .map(|(index, arg)| {
-                (fn_sig.inputs[index], &*arg.pat)
-            })
-            .collect();
-
-    let (mut mir, scope_auxiliary) =
-        build::construct(cx,
-                         span,
-                         fn_id,
-                         body.id,
-                         implicit_arg_tys,
-                         arguments,
-                         fn_sig.output,
-                         body);
-
-    match cx.tcx().node_id_to_type(fn_id).sty {
-        ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
-            // RustCall pseudo-ABI untuples the last argument.
-            if let Some(arg_decl) = mir.arg_decls.last_mut() {
-                arg_decl.spread = true;
-            }
-        }
-        _ => {}
-    }
-
-    pretty::dump_mir(cx.tcx(),
-                     "mir_map",
-                     &0,
-                     fn_id,
-                     &mir,
-                     Some(&scope_auxiliary));
-
-    Ok(mir)
-}
-
 fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
                              closure_expr_id: ast::NodeId,
                              body_id: ast::NodeId)