about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-10-21 15:46:30 -0400
committerNiko Matsakis <niko@alum.mit.edu>2015-11-03 04:34:59 -0500
commit6d7c66e6e82229134fcc5a2b5a23545f8a17f1ce (patch)
treeb8107ccf92cc18b283ef11248d84864421a83e03
parentfffe0757086b8f381226cb5ddcb6c129a815b96d (diff)
downloadrust-6d7c66e6e82229134fcc5a2b5a23545f8a17f1ce.tar.gz
rust-6d7c66e6e82229134fcc5a2b5a23545f8a17f1ce.zip
Introduce a "liberated fn sigs" map so that we have easy access to this
information when constructing MIR.
-rw-r--r--src/librustc/middle/ty/context.rs8
-rw-r--r--src/librustc_typeck/check/mod.rs19
-rw-r--r--src/librustc_typeck/check/regionck.rs27
-rw-r--r--src/librustc_typeck/check/writeback.rs23
4 files changed, 53 insertions, 24 deletions
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index 830232cf373..a8f045074bd 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -121,6 +121,13 @@ pub struct Tables<'tcx> {
     /// Records the type of each closure. The def ID is the ID of the
     /// expression defining the closure.
     pub closure_kinds: DefIdMap<ty::ClosureKind>,
+
+    /// For each fn, records the "liberated" types of its arguments
+    /// and return type. Liberated means that all bound regions
+    /// (including late-bound regions) are replaced with free
+    /// equivalents. This table is not used in trans (since regions
+    /// are erased there) and hence is not serialized to metadata.
+    pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,
 }
 
 impl<'tcx> Tables<'tcx> {
@@ -133,6 +140,7 @@ impl<'tcx> Tables<'tcx> {
             upvar_capture_map: FnvHashMap(),
             closure_tys: DefIdMap(),
             closure_kinds: DefIdMap(),
+            liberated_fn_sigs: NodeMap(),
         }
     }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f085ce23e3f..dc2b2b75ab6 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -164,11 +164,6 @@ pub struct Inherited<'a, 'tcx: 'a> {
 
     tables: &'a RefCell<ty::Tables<'tcx>>,
 
-    // A mapping from each fn's id to its signature, with all bound
-    // regions replaced with free ones. Unlike the other tables, this
-    // one is never copied into the tcx: it is only used by regionck.
-    fn_sig_map: RefCell<NodeMap<Vec<Ty<'tcx>>>>,
-
     // When we process a call like `c()` where `c` is a closure type,
     // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
     // `FnOnce` closure. In that case, we defer full resolution of the
@@ -314,7 +309,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
             infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), true),
             locals: RefCell::new(NodeMap()),
             tables: tables,
-            fn_sig_map: RefCell::new(NodeMap()),
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
         }
@@ -620,22 +614,13 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
         ccx: ccx
     };
 
-    // Remember return type so that regionck can access it later.
-    let mut fn_sig_tys: Vec<Ty> =
-        arg_tys.iter()
-        .cloned()
-        .collect();
-
     if let ty::FnConverging(ret_ty) = ret_ty {
         fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
-        fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments
     }
 
-    debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
-           fn_id,
-           fn_sig_tys);
+    debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);
 
-    inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys);
+    inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
 
     {
         let mut visit = GatherLocalsVisitor { fcx: &fcx, };
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 6e60f926b7c..3cdc9b55944 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -284,19 +284,32 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
         // When we enter a function, we can derive
         debug!("visit_fn_body(id={})", id);
 
-        let fn_sig_map = self.fcx.inh.fn_sig_map.borrow();
-        let fn_sig = match fn_sig_map.get(&id) {
-            Some(f) => f,
-            None => {
-                self.tcx().sess.bug(
-                    &format!("No fn-sig entry for id={}", id));
+        let fn_sig = {
+            let fn_sig_map = &self.infcx().tables.borrow().liberated_fn_sigs;
+            match fn_sig_map.get(&id) {
+                Some(f) => f.clone(),
+                None => {
+                    self.tcx().sess.bug(
+                        &format!("No fn-sig entry for id={}", id));
+                }
             }
         };
 
         let old_region_bounds_pairs_len = self.region_bound_pairs.len();
 
+        // Collect the types from which we create inferred bounds.
+        // For the return type, if diverging, substitute `bool` just
+        // because it will have no effect.
+        //
+        // FIXME(#25759) return types should not be implied bounds
+        let fn_sig_tys: Vec<_> =
+            fn_sig.inputs.iter()
+                         .cloned()
+                         .chain(Some(fn_sig.output.unwrap_or(self.tcx().types.bool)))
+                         .collect();
+
         let old_body_id = self.set_body_id(body.id);
-        self.relate_free_regions(&fn_sig[..], body.id, span);
+        self.relate_free_regions(&fn_sig_tys[..], body.id, span);
         link_fn_args(self,
                      self.tcx().region_maps.node_extent(body.id),
                      &fn_decl.inputs[..]);
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 2c18a245159..cfab28f923e 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
     wbcx.visit_expr(e);
     wbcx.visit_upvar_borrow_map();
     wbcx.visit_closures();
+    wbcx.visit_liberated_fn_sigs();
 }
 
 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
     }
     wbcx.visit_upvar_borrow_map();
     wbcx.visit_closures();
+    wbcx.visit_liberated_fn_sigs();
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -361,6 +363,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         }
     }
 
+    fn visit_liberated_fn_sigs(&self) {
+        for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() {
+            let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
+            self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
+        }
+    }
+
     fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
         t.fold_with(&mut Resolver::new(self.fcx, reason))
     }
@@ -376,6 +385,7 @@ enum ResolveReason {
     ResolvingPattern(Span),
     ResolvingUpvar(ty::UpvarId),
     ResolvingClosure(DefId),
+    ResolvingFnSig(ast::NodeId),
 }
 
 impl ResolveReason {
@@ -387,6 +397,9 @@ impl ResolveReason {
             ResolvingUpvar(upvar_id) => {
                 tcx.expr_span(upvar_id.closure_expr_id)
             }
+            ResolvingFnSig(id) => {
+                tcx.map.span(id)
+            }
             ResolvingClosure(did) => {
                 if let Some(node_id) = tcx.map.as_local_node_id(did) {
                     tcx.expr_span(node_id)
@@ -463,6 +476,16 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
                     span_err!(self.tcx.sess, span, E0196,
                               "cannot determine a type for this closure")
                 }
+
+                ResolvingFnSig(id) => {
+                    // any failures here should also fail when
+                    // resolving the patterns, closure types, or
+                    // something else.
+                    let span = self.reason.span(self.tcx);
+                    self.tcx.sess.delay_span_bug(
+                        span,
+                        &format!("cannot resolve some aspect of fn sig for {:?}", id));
+                }
             }
         }
     }