about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-11-08 09:45:48 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-11-18 07:47:37 -0500
commit2dff9a49e5be5857610336e585eb8e7267dd142e (patch)
tree420514091c98b9fdae3c2d8c2331a2178e669095
parent716f75b1b84e6f615b4ab80965dfa9a2fc566a31 (diff)
downloadrust-2dff9a49e5be5857610336e585eb8e7267dd142e.tar.gz
rust-2dff9a49e5be5857610336e585eb8e7267dd142e.zip
stop using the `closure_kinds` query / table for anything
Closure Kind is now extracted from the closure substs exclusively.
-rw-r--r--src/librustc/infer/mod.rs25
-rw-r--r--src/librustc/middle/mem_categorization.rs17
-rw-r--r--src/librustc/traits/error_reporting.rs4
-rw-r--r--src/librustc/traits/fulfill.rs2
-rw-r--r--src/librustc/traits/select.rs6
-rw-r--r--src/librustc/ty/instance.rs2
-rw-r--r--src/librustc/ty/sty.rs19
-rw-r--r--src/librustc_mir/build/mod.rs8
-rw-r--r--src/librustc_trans/common.rs2
-rw-r--r--src/librustc_trans_utils/monomorphize.rs2
-rw-r--r--src/librustc_typeck/check/callee.rs6
-rw-r--r--src/librustc_typeck/check/closure.rs18
-rw-r--r--src/librustc_typeck/check/upvar.rs103
-rw-r--r--src/test/compile-fail/issue-22638.rs2
14 files changed, 107 insertions, 109 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 4f923f0b249..905e45bf9f0 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1463,26 +1463,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
     }
 
+    /// Obtains the latest type of the given closure; this may be a
+    /// closure in the current function, in which case its
+    /// `ClosureKind` may not yet be known.
     pub fn closure_kind(&self,
-                        def_id: DefId)
+                        closure_def_id: DefId,
+                        closure_substs: ty::ClosureSubsts<'tcx>)
                         -> Option<ty::ClosureKind>
     {
-        if let Some(tables) = self.in_progress_tables {
-            if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
-                let hir_id = self.tcx.hir.node_to_hir_id(id);
-                return tables.borrow()
-                             .closure_kinds()
-                             .get(hir_id)
-                             .cloned()
-                             .map(|(kind, _)| kind);
-            }
-        }
-
-        // During typeck, ALL closures are local. But afterwards,
-        // during trans, we see closure ids from other traits.
-        // That may require loading the closure data out of the
-        // cstore.
-        Some(self.tcx.closure_kind(def_id))
+        let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
+        let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
+        closure_kind_ty.to_opt_closure_kind()
     }
 
     /// Obtain the signature of a function or closure.
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 2c6bcc654a5..a41a8093071 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -750,10 +750,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         let kind = match self.node_ty(fn_hir_id)?.sty {
             ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
-            ty::TyClosure(..) => {
-                match self.tables.closure_kinds().get(fn_hir_id) {
-                    Some(&(kind, _)) => kind,
-                    None => span_bug!(span, "missing closure kind"),
+            ty::TyClosure(closure_def_id, closure_substs) => {
+                match self.infcx {
+                    // During upvar inference we may not know the
+                    // closure kind, just use `Fn`.
+                    Some(infcx) =>
+                        infcx.closure_kind(closure_def_id, closure_substs)
+                             .unwrap_or(ty::ClosureKind::Fn),
+
+                    None =>
+                        self.tcx.global_tcx()
+                                .lift(&closure_substs)
+                                .expect("no inference cx, but inference variables in closure ty")
+                                .closure_kind(closure_def_id, self.tcx.global_tcx())
                 }
             }
             ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index caed3639b56..ccea981b78e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -643,8 +643,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                             violations)
                     }
 
-                    ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => {
-                        let found_kind = self.closure_kind(closure_def_id).unwrap();
+                    ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
+                        let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
                         let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
                         let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
                         let mut err = struct_span_err!(
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 1595679e9eb..6b681322c9b 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -439,7 +439,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         }
 
         ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-            match closure_substs.opt_closure_kind(closure_def_id, selcx.tcx()) {
+            match selcx.infcx().closure_kind(closure_def_id, closure_substs) {
                 Some(closure_kind) => {
                     if closure_kind.extends(kind) {
                         Ok(Some(vec![]))
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 2ab44b9c8bb..fba894d528e 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                match closure_substs.opt_closure_kind(closure_def_id, self.tcx()) {
+                match self.infcx.closure_kind(closure_def_id, closure_substs) {
                     Some(closure_kind) => {
                         if closure_kind.extends(kind) {
                             EvaluatedToOk
@@ -1593,10 +1593,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters
         match obligation.self_ty().skip_binder().sty {
-            ty::TyClosure(closure_def_id, _) => {
+            ty::TyClosure(closure_def_id, closure_substs) => {
                 debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}",
                        kind, obligation);
-                match self.infcx.closure_kind(closure_def_id) {
+                match self.infcx.closure_kind(closure_def_id, closure_substs) {
                     Some(closure_kind) => {
                         debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
                         if closure_kind.extends(kind) {
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 6ea953c3f73..70636f8b6fe 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -189,7 +189,7 @@ fn resolve_closure<'a, 'tcx>(
                    requested_kind: ty::ClosureKind)
 -> Instance<'tcx>
 {
-    let actual_kind = tcx.closure_kind(def_id);
+    let actual_kind = substs.closure_kind(def_id, tcx);
 
     match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
         Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index bc55ffdc31f..e20db5e3807 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -290,16 +290,8 @@ impl<'tcx> ClosureSubsts<'tcx> {
         upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
     }
 
-    /// Returns the closure kind for this closure; may return `None`
-    /// if inference has not yet completed.
-    pub fn opt_closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>)
-                            -> Option<ty::ClosureKind> {
-        let closure_kind_ty = self.closure_kind_ty(def_id, tcx);
-        closure_kind_ty.to_opt_closure_kind()
-    }
-
-    /// Returns the closure kind for this closure; may return `None`
-    /// if inference has not yet completed.
+    /// Returns the closure kind for this closure; may return a type
+    /// variable during inference.
     pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
         self.split(def_id, tcx).closure_kind_ty
     }
@@ -307,9 +299,10 @@ impl<'tcx> ClosureSubsts<'tcx> {
 
 impl<'tcx> ClosureSubsts<'tcx> {
     /// Returns the closure kind for this closure; only usable outside
-    /// of an inference context.
+    /// of an inference context, because in that context we know that
+    /// there are no type variables.
     pub fn closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::ClosureKind {
-        self.opt_closure_kind(def_id, tcx).unwrap()
+        self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap()
     }
 }
 
@@ -1514,6 +1507,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
             TyInfer(_) => None,
 
+            TyError => Some(ty::ClosureKind::Fn),
+
             _ => bug!("cannot convert type `{:?}` to a closure kind", self),
         }
     }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index e722a589b66..c4966c012c7 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -248,14 +248,18 @@ pub fn closure_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id);
     let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id);
 
-    let closure_def_id = tcx.hir.local_def_id(closure_expr_id);
+    let (closure_def_id, closure_substs) = match closure_ty.sty {
+        ty::TyClosure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
+        _ => bug!("closure expr does not have closure type: {:?}", closure_ty)
+    };
+
     let region = ty::ReFree(ty::FreeRegion {
         scope: closure_def_id,
         bound_region: ty::BoundRegion::BrEnv,
     });
     let region = tcx.mk_region(region);
 
-    match tcx.closure_kind(closure_def_id) {
+    match closure_substs.closure_kind_ty(closure_def_id, tcx).to_opt_closure_kind().unwrap() {
         ty::ClosureKind::Fn =>
             tcx.mk_ref(region,
                        ty::TypeAndMut { ty: closure_ty,
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index e3856cabcf9..7309b05d5a0 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -511,7 +511,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs);
 
             let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
-            let env_ty = match tcx.closure_kind(def_id) {
+            let env_ty = match substs.closure_kind(def_id, tcx) {
                 ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty),
                 ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty),
                 ty::ClosureKind::FnOnce => ty,
diff --git a/src/librustc_trans_utils/monomorphize.rs b/src/librustc_trans_utils/monomorphize.rs
index ab61dacf010..1f8d273d8fb 100644
--- a/src/librustc_trans_utils/monomorphize.rs
+++ b/src/librustc_trans_utils/monomorphize.rs
@@ -86,7 +86,7 @@ pub fn resolve_closure<'a, 'tcx> (
     requested_kind: ty::ClosureKind)
     -> Instance<'tcx>
 {
-    let actual_kind = tcx.closure_kind(def_id);
+    let actual_kind = substs.closure_kind(def_id, tcx);
 
     match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
         Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 91ce4511a31..8f409b68752 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // Check whether this is a call to a closure where we
                 // haven't yet decided on whether the closure is fn vs
                 // fnmut vs fnonce. If so, we have to defer further processing.
-                if self.closure_kind(def_id).is_none() {
+                if self.closure_kind(def_id, substs).is_none() {
                     let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs);
                     let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
                                                                    infer::FnCall,
@@ -122,6 +122,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         adjustments,
                         fn_sig,
                         closure_def_id: def_id,
+                        closure_substs: substs,
                     });
                     return Some(CallStep::DeferredClosure(fn_sig));
                 }
@@ -336,6 +337,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
     adjustments: Vec<Adjustment<'tcx>>,
     fn_sig: ty::FnSig<'tcx>,
     closure_def_id: DefId,
+    closure_substs: ty::ClosureSubsts<'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
@@ -344,7 +346,7 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
 
         // we should not be invoked until the closure kind has been
         // determined by upvar inference
-        assert!(fcx.closure_kind(self.closure_def_id).is_some());
+        assert!(fcx.closure_kind(self.closure_def_id, self.closure_substs).is_some());
 
         // We may now know enough to figure out fn vs fnmut etc.
         match fcx.try_overloaded_call_traits(self.call_expr,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 1f96afe3ac8..5eda205c26d 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -107,6 +107,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let closure_type = self.tcx.mk_closure(expr_def_id, substs);
 
         if let Some(interior) = interior {
+            self.demand_eqtype(expr.span,
+                               ty::ClosureKind::FnOnce.to_ty(self.tcx),
+                               substs.closure_kind_ty(expr_def_id, self.tcx));
             return self.tcx.mk_generator(expr_def_id, substs, interior);
         }
 
@@ -135,15 +138,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             opt_kind
         );
 
-        {
-            let mut tables = self.tables.borrow_mut();
-            tables.closure_tys_mut().insert(expr.hir_id, sig);
-            match opt_kind {
-                Some(kind) => {
-                    tables.closure_kinds_mut().insert(expr.hir_id, (kind, None));
-                }
-                None => {}
-            }
+        self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig);
+        if let Some(kind) = opt_kind {
+            self.tables.borrow_mut().closure_kinds_mut().insert(expr.hir_id, (kind, None));
+            self.demand_eqtype(expr.span,
+                               kind.to_ty(self.tcx),
+                               substs.closure_kind_ty(expr_def_id, self.tcx));
         }
 
         closure_type
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index c4cdd958680..048f53f2988 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -46,7 +46,6 @@ use middle::expr_use_visitor as euv;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::TypeFoldable;
 use rustc::infer::UpvarRegion;
 use syntax::ast;
 use syntax_pos::Span;
@@ -158,40 +157,58 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         });
 
-        {
-            let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
-            let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
-            let mut delegate = InferBorrowKind {
-                fcx: self,
-                adjust_closure_kinds: FxHashMap(),
-                adjust_upvar_captures: ty::UpvarCaptureMap::default(),
-            };
-            euv::ExprUseVisitor::with_infer(
-                &mut delegate,
-                &self.infcx,
-                self.param_env,
-                region_scope_tree,
-                &self.tables.borrow(),
-            ).consume_body(body);
-
-            // Write the adjusted values back into the main tables.
-            if infer_kind {
-                if let Some(kind) = delegate
-                    .adjust_closure_kinds
-                    .remove(&closure_def_id.to_local())
-                {
-                    self.tables
-                        .borrow_mut()
-                        .closure_kinds_mut()
-                        .insert(closure_hir_id, kind);
-                }
+        // Extract the type of the closure.
+        let (def_id, closure_substs) = match self.node_ty(closure_hir_id).sty {
+            ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => (def_id, substs),
+            ref t => {
+                span_bug!(
+                    span,
+                    "type of closure expr {:?} is not a closure {:?}",
+                    closure_node_id,
+                    t
+                );
+            }
+        };
+
+        let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
+        let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
+        let mut delegate = InferBorrowKind {
+            fcx: self,
+            adjust_closure_kinds: FxHashMap(),
+            adjust_upvar_captures: ty::UpvarCaptureMap::default(),
+        };
+        euv::ExprUseVisitor::with_infer(
+            &mut delegate,
+            &self.infcx,
+            self.param_env,
+            region_scope_tree,
+            &self.tables.borrow(),
+        ).consume_body(body);
+
+        // Write the adjusted values back into the main tables.
+        if infer_kind {
+            let opt_adjusted = delegate.adjust_closure_kinds.remove(&closure_def_id.to_local());
+            let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx);
+            if let Some((kind, origin)) = opt_adjusted {
+                self.tables
+                    .borrow_mut()
+                    .closure_kinds_mut()
+                    .insert(closure_hir_id, (kind, origin));
+
+                self.demand_eqtype(span, kind.to_ty(self.tcx), closure_kind_ty);
+            } else {
+                // If there are only reads, or no upvars, then the
+                // default of `Fn` will never *have* to be adjusted, so there will be
+                // no entry in the map.
+                self.demand_eqtype(span, ty::ClosureKind::Fn.to_ty(self.tcx), closure_kind_ty);
             }
-            self.tables
-                .borrow_mut()
-                .upvar_capture_map
-                .extend(delegate.adjust_upvar_captures);
         }
 
+        self.tables
+            .borrow_mut()
+            .upvar_capture_map
+            .extend(delegate.adjust_upvar_captures);
+
         // Now that we've analyzed the closure, we know how each
         // variable is borrowed, and we know what traits the closure
         // implements (Fn vs FnMut etc). We now have some updates to do
@@ -204,27 +221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // C, then the type would have infinite size (and the
         // inference algorithm will reject it).
 
-        // Extract the type variables UV0...UVn.
-        let (def_id, closure_substs) = match self.node_ty(closure_hir_id).sty {
-            ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => (def_id, substs),
-            ref t => {
-                span_bug!(
-                    span,
-                    "type of closure expr {:?} is not a closure {:?}",
-                    closure_node_id,
-                    t
-                );
-            }
-        };
-
-        // Equate the type variable representing the closure kind.
-        let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx);
-        if closure_kind_ty.needs_infer() {
-            let final_closure_kind = self.tables.borrow().closure_kinds()[closure_hir_id].0;
-            self.demand_eqtype(span, final_closure_kind.to_ty(self.tcx), closure_kind_ty);
-        }
-
-        // Equate the type variables with the actual types.
+        // Equate the type variables for the upvars with the actual types.
         let final_upvar_tys = self.final_upvar_tys(closure_node_id);
         debug!(
             "analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
diff --git a/src/test/compile-fail/issue-22638.rs b/src/test/compile-fail/issue-22638.rs
index 53b0d9f4e9f..1c534ebbd43 100644
--- a/src/test/compile-fail/issue-22638.rs
+++ b/src/test/compile-fail/issue-22638.rs
@@ -19,7 +19,6 @@ struct A (B);
 
 impl A {
     pub fn matches<F: Fn()>(&self, f: &F) {
-        //~^ ERROR reached the recursion limit while instantiating `A::matches::<[closure
         let &A(ref term) = self;
         term.matches(f);
     }
@@ -59,6 +58,7 @@ struct D (Box<A>);
 
 impl D {
     pub fn matches<F: Fn()>(&self, f: &F) {
+        //~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure
         let &D(ref a) = self;
         a.matches(f)
     }