about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-05-12 11:44:31 -0400
committerNiko Matsakis <niko@alum.mit.edu>2017-05-22 15:37:10 -0400
commitb46c1a95d0fd309c4d6a8e42da7cc2da034326b9 (patch)
treeaecbce20b797bc3d8358d3e19f08d52ad776967a
parent5a5c265e24cc79a8e28f01930380cb8a2481165c (diff)
downloadrust-b46c1a95d0fd309c4d6a8e42da7cc2da034326b9.tar.gz
rust-b46c1a95d0fd309c4d6a8e42da7cc2da034326b9.zip
move `needs_drop` into a query
-rw-r--r--src/librustc/dep_graph/dep_node.rs2
-rw-r--r--src/librustc/ty/maps.rs12
-rw-r--r--src/librustc/ty/util.rs178
3 files changed, 86 insertions, 106 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 2620a9c8f2d..12a3e5bfaa0 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -111,6 +111,7 @@ pub enum DepNode<D: Clone + Debug> {
     IsCopy(D),
     IsSized(D),
     IsFreeze(D),
+    NeedsDrop(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -240,6 +241,7 @@ impl<D: Clone + Debug> DepNode<D> {
             IsCopy(ref d) => op(d).map(IsCopy),
             IsSized(ref d) => op(d).map(IsSized),
             IsFreeze(ref d) => op(d).map(IsFreeze),
+            NeedsDrop(ref d) => op(d).map(NeedsDrop),
             Hir(ref d) => op(d).map(Hir),
             HirBody(ref d) => op(d).map(HirBody),
             MetaData(ref d) => op(d).map(MetaData),
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 2c3dae8493a..5f2bc03ed9e 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -271,6 +271,12 @@ impl<'tcx> QueryDescription for queries::is_freeze_raw<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> {
+    fn describe(_tcx: TyCtxt, env: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> String {
+        format!("computing whether `{}` needs drop", env.value)
+    }
+}
+
 impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> {
     fn describe(tcx: TyCtxt, def_id: DefId) -> String {
         format!("computing the supertraits of `{}`",
@@ -891,6 +897,7 @@ define_maps! { <'tcx>
     [] is_copy_raw: is_copy_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool,
     [] is_sized_raw: is_sized_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool,
     [] is_freeze_raw: is_freeze_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool,
+    [] needs_drop_raw: needs_drop_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool,
 }
 
 fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -949,3 +956,8 @@ fn is_freeze_dep_node<'tcx>(_: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> D
     let krate_def_id = DefId::local(CRATE_DEF_INDEX);
     DepNode::IsSized(krate_def_id)
 }
+
+fn needs_drop_dep_node<'tcx>(_: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
+    let krate_def_id = DefId::local(CRATE_DEF_INDEX);
+    DepNode::NeedsDrop(krate_def_id)
+}
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index da2552d37e2..0c2f4efccd5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -15,14 +15,13 @@ use hir::map::DefPathData;
 use infer::InferCtxt;
 use ich::{StableHashingContext, NodeIdHashingMode};
 use traits::{self, Reveal};
-use ty::{self, Ty, TyCtxt, TypeFlags, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::ParameterEnvironment;
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
 use ty::subst::{Subst, Kind};
 use ty::TypeVariants::*;
 use util::common::ErrorReported;
-use util::nodemap::FxHashSet;
 use middle::lang_items;
 
 use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
@@ -754,110 +753,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                       tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       param_env: ty::ParameterEnvironment<'tcx>)
                       -> bool {
-        if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
-            return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
-        }
-
-        self.needs_drop_uncached(tcx, param_env, &mut FxHashSet())
-    }
-
-    fn needs_drop_inner(&'tcx self,
-                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                        param_env: ty::ParameterEnvironment<'tcx>,
-                        stack: &mut FxHashSet<Ty<'tcx>>)
-                        -> bool {
-        if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
-            return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
-        }
-
-        // This should be reported as an error by `check_representable`.
-        //
-        // Consider the type as not needing drop in the meanwhile to avoid
-        // further errors.
-        if let Some(_) = stack.replace(self) {
-            return false;
-        }
-
-        let needs_drop = self.needs_drop_uncached(tcx, param_env, stack);
-
-        // "Pop" the cycle detection "stack".
-        stack.remove(self);
-
-        needs_drop
-    }
-
-    fn needs_drop_uncached(&'tcx self,
-                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           param_env: ty::ParameterEnvironment<'tcx>,
-                           stack: &mut FxHashSet<Ty<'tcx>>)
-                           -> bool {
-        assert!(!self.needs_infer());
-
-        let result = match self.sty {
-            // Fast-path for primitive types
-            ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
-            ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
-            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
-            ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
-
-            // Issue #22536: We first query type_moves_by_default.  It sees a
-            // normalized version of the type, and therefore will definitely
-            // know whether the type implements Copy (and thus needs no
-            // cleanup/drop/zeroing) ...
-            _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false,
-
-            // ... (issue #22536 continued) but as an optimization, still use
-            // prior logic of asking for the structural "may drop".
-
-            // FIXME(#22815): Note that this is a conservative heuristic;
-            // it may report that the type "may drop" when actual type does
-            // not actually have a destructor associated with it. But since
-            // the type absolutely did not have the `Copy` bound attached
-            // (see above), it is sound to treat it as having a destructor.
-
-            // User destructors are the only way to have concrete drop types.
-            ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
-
-            // Can refer to a type which may drop.
-            // FIXME(eddyb) check this against a ParameterEnvironment.
-            ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
-            ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
-
-            // Structural recursion.
-            ty::TyArray(ty, _) | ty::TySlice(ty) => {
-                ty.needs_drop_inner(tcx, param_env, stack)
-            }
-
-            ty::TyClosure(def_id, ref substs) => {
-                substs.upvar_tys(def_id, tcx)
-                    .any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
-            }
-
-            ty::TyTuple(ref tys, _) => {
-                tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
-            }
-
-            // unions don't have destructors regardless of the child types
-            ty::TyAdt(def, _) if def.is_union() => false,
-
-            ty::TyAdt(def, substs) => {
-                def.variants.iter().any(|v| {
-                    v.fields.iter().any(|f| {
-                        f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack)
-                    })
-                })
-            }
-        };
-
-        if !self.has_param_types() && !self.has_self_ty() {
-            self.flags.set(self.flags.get() | if result {
-                TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP
-            } else {
-                TypeFlags::NEEDS_DROP_CACHED
-            });
-        }
-
-        result
+        tcx.needs_drop_raw(param_env.and(self))
     }
 
     #[inline]
@@ -1075,11 +971,81 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
        .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
 }
 
+fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            query: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>)
+                            -> bool
+{
+    let (param_env, ty) = query.into_parts();
+
+    let needs_drop = |ty: Ty<'tcx>| -> bool {
+        match ty::queries::needs_drop_raw::try_get(tcx, DUMMY_SP, param_env.and(ty)) {
+            Ok(v) => v,
+            Err(_) => {
+                // Cycles should be reported as an error by `check_representable`.
+                //
+                // Consider the type as not needing drop in the meanwhile to avoid
+                // further errors.
+                false
+            }
+        }
+    };
+
+    assert!(!ty.needs_infer());
+
+    match ty.sty {
+        // Fast-path for primitive types
+        ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
+        ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
+        ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
+        ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
+
+        // Issue #22536: We first query type_moves_by_default.  It sees a
+        // normalized version of the type, and therefore will definitely
+        // know whether the type implements Copy (and thus needs no
+        // cleanup/drop/zeroing) ...
+        _ if !ty.moves_by_default(tcx, param_env, DUMMY_SP) => false,
+
+        // ... (issue #22536 continued) but as an optimization, still use
+        // prior logic of asking for the structural "may drop".
+
+        // FIXME(#22815): Note that this is a conservative heuristic;
+        // it may report that the type "may drop" when actual type does
+        // not actually have a destructor associated with it. But since
+        // the type absolutely did not have the `Copy` bound attached
+        // (see above), it is sound to treat it as having a destructor.
+
+        // User destructors are the only way to have concrete drop types.
+        ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
+
+        // Can refer to a type which may drop.
+        // FIXME(eddyb) check this against a ParameterEnvironment.
+        ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
+        ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
+
+        // Structural recursion.
+        ty::TyArray(ty, _) | ty::TySlice(ty) => needs_drop(ty),
+
+        ty::TyClosure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop),
+
+        ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop),
+
+        // unions don't have destructors regardless of the child types
+        ty::TyAdt(def, _) if def.is_union() => false,
+
+        ty::TyAdt(def, substs) =>
+            def.variants.iter().any(
+                |variant| variant.fields.iter().any(
+                    |field| needs_drop(field.ty(tcx, substs)))),
+    }
+}
+
+
 pub fn provide(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         is_copy_raw,
         is_sized_raw,
         is_freeze_raw,
+        needs_drop_raw,
         ..*providers
     };
 }