about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2020-06-10 09:30:39 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2020-06-21 10:22:21 +0100
commitf802ee1f59439f08ed787fc530d30fd35d6d419b (patch)
treedb8001bfa300a22da5def707c92a015812794bb6
parent8ea55f1a99fb8c539279fd367d2cfce185fc0d0b (diff)
downloadrust-f802ee1f59439f08ed787fc530d30fd35d6d419b.tar.gz
rust-f802ee1f59439f08ed787fc530d30fd35d6d419b.zip
Cache flags and escaping vars for predicates
Also hash predicates by address
-rw-r--r--src/librustc_middle/arena.rs1
-rw-r--r--src/librustc_middle/ty/context.rs57
-rw-r--r--src/librustc_middle/ty/flags.rs82
-rw-r--r--src/librustc_middle/ty/fold.rs16
-rw-r--r--src/librustc_middle/ty/mod.rs46
-rw-r--r--src/librustc_middle/ty/structural_impls.rs28
6 files changed, 202 insertions, 28 deletions
diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs
index aaef9871aa5..4f1889aeb16 100644
--- a/src/librustc_middle/arena.rs
+++ b/src/librustc_middle/arena.rs
@@ -100,6 +100,7 @@ macro_rules! arena_types {
 
             // Interned types
             [] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>;
+            [] predicates: rustc_middle::ty::PredicateInner<$tcx>, rustc_middle::ty::PredicateInner<'_x>;
 
             // HIR query types
             [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>;
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index 1b909b42fdf..56f4ae9e984 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -19,8 +19,9 @@ use crate::ty::TyKind::*;
 use crate::ty::{
     self, query, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
     DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy,
-    IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy,
-    Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
+    IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
+    ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
+    TyVid, TypeAndMut,
 };
 use rustc_ast::ast;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -76,7 +77,7 @@ pub struct CtxtInterners<'tcx> {
     canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo>>,
     region: InternedSet<'tcx, RegionKind>,
     existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
-    predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>,
+    predicate: InternedSet<'tcx, PredicateInner<'tcx>>,
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@@ -95,7 +96,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             region: Default::default(),
             existential_predicates: Default::default(),
             canonical_var_infos: Default::default(),
-            predicate_kind: Default::default(),
+            predicate: Default::default(),
             predicates: Default::default(),
             projs: Default::default(),
             place_elems: Default::default(),
@@ -123,6 +124,23 @@ impl<'tcx> CtxtInterners<'tcx> {
             })
             .0
     }
+
+    #[inline(never)]
+    fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
+        self.predicate
+            .intern(kind, |kind| {
+                let flags = super::flags::FlagComputation::for_predicate(&kind);
+
+                let predicate_struct = PredicateInner {
+                    kind,
+                    flags: flags.flags,
+                    outer_exclusive_binder: flags.outer_exclusive_binder,
+                };
+
+                Interned(self.arena.alloc(predicate_struct))
+            })
+            .0
+    }
 }
 
 pub struct CommonTypes<'tcx> {
@@ -1627,7 +1645,7 @@ macro_rules! nop_list_lift {
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>}
+nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
 
 nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
 nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
@@ -1986,6 +2004,26 @@ impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
         &self.0.kind
     }
 }
+// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
+impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
+    fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+        self.0.kind == other.0.kind
+    }
+}
+
+impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
+
+impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        self.0.kind.hash(s)
+    }
+}
+
+impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateInner<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
+        &self.0.kind
+    }
+}
 
 // N.B., an `Interned<List<T>>` compares and hashes as its elements.
 impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
@@ -2052,11 +2090,10 @@ macro_rules! direct_interners {
     }
 }
 
-direct_interners!(
+direct_interners! {
     region: mk_region(RegionKind),
     const_: mk_const(Const<'tcx>),
-    predicate_kind: intern_predicate_kind(PredicateKind<'tcx>),
-);
+}
 
 macro_rules! slice_interners {
     ($($field:ident: $method:ident($ty:ty)),+) => (
@@ -2127,8 +2164,8 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
-        let kind = self.intern_predicate_kind(kind);
-        Predicate { kind }
+        let inner = self.interners.intern_predicate(kind);
+        Predicate { inner }
     }
 
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs
index d13be4f4285..c782eee9387 100644
--- a/src/librustc_middle/ty/flags.rs
+++ b/src/librustc_middle/ty/flags.rs
@@ -1,5 +1,6 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, InferConst, Ty, TypeFlags};
+use std::slice;
 
 #[derive(Debug)]
 pub struct FlagComputation {
@@ -21,6 +22,12 @@ impl FlagComputation {
         result
     }
 
+    pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation {
+        let mut result = FlagComputation::new();
+        result.add_predicate_kind(kind);
+        result
+    }
+
     pub fn for_const(c: &ty::Const<'_>) -> TypeFlags {
         let mut result = FlagComputation::new();
         result.add_const(c);
@@ -32,7 +39,7 @@ impl FlagComputation {
     }
 
     /// indicates that `self` refers to something at binding level `binder`
-    fn add_binder(&mut self, binder: ty::DebruijnIndex) {
+    fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
         let exclusive_binder = binder.shifted_in(1);
         self.add_exclusive_binder(exclusive_binder);
     }
@@ -46,7 +53,7 @@ impl FlagComputation {
 
     /// Adds the flags/depth from a set of types that appear within the current type, but within a
     /// region binder.
-    fn add_bound_computation(&mut self, computation: &FlagComputation) {
+    fn add_bound_computation(&mut self, computation: FlagComputation) {
         self.add_flags(computation.flags);
 
         // The types that contributed to `computation` occurred within
@@ -84,7 +91,7 @@ impl FlagComputation {
             &ty::GeneratorWitness(ref ts) => {
                 let mut computation = FlagComputation::new();
                 computation.add_tys(&ts.skip_binder()[..]);
-                self.add_bound_computation(&computation);
+                self.add_bound_computation(computation);
             }
 
             &ty::Closure(_, ref substs) => {
@@ -92,7 +99,7 @@ impl FlagComputation {
             }
 
             &ty::Bound(debruijn, _) => {
-                self.add_binder(debruijn);
+                self.add_bound_var(debruijn);
             }
 
             &ty::Placeholder(..) => {
@@ -133,12 +140,12 @@ impl FlagComputation {
                         ty::ExistentialPredicate::Projection(p) => {
                             let mut proj_computation = FlagComputation::new();
                             proj_computation.add_existential_projection(&p);
-                            self.add_bound_computation(&proj_computation);
+                            self.add_bound_computation(proj_computation);
                         }
                         ty::ExistentialPredicate::AutoTrait(_) => {}
                     }
                 }
-                self.add_bound_computation(&computation);
+                self.add_bound_computation(computation);
                 self.add_region(r);
             }
 
@@ -172,6 +179,63 @@ impl FlagComputation {
         }
     }
 
+    fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) {
+        match kind {
+            ty::PredicateKind::Trait(trait_pred, _constness) => {
+                let mut computation = FlagComputation::new();
+                computation.add_substs(trait_pred.skip_binder().trait_ref.substs);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::RegionOutlives(poly_outlives) => {
+                let mut computation = FlagComputation::new();
+                let ty::OutlivesPredicate(a, b) = poly_outlives.skip_binder();
+                computation.add_region(a);
+                computation.add_region(b);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::TypeOutlives(poly_outlives) => {
+                let mut computation = FlagComputation::new();
+                let ty::OutlivesPredicate(ty, region) = poly_outlives.skip_binder();
+                computation.add_ty(ty);
+                computation.add_region(region);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::Subtype(poly_subtype) => {
+                let mut computation = FlagComputation::new();
+                let ty::SubtypePredicate { a_is_expected: _, a, b } = poly_subtype.skip_binder();
+                computation.add_ty(a);
+                computation.add_ty(b);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::Projection(projection) => {
+                let mut computation = FlagComputation::new();
+                let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder();
+                computation.add_projection_ty(projection_ty);
+                computation.add_ty(ty);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::WellFormed(arg) => {
+                self.add_substs(slice::from_ref(arg));
+            }
+            ty::PredicateKind::ObjectSafe(_def_id) => {}
+            ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
+                self.add_substs(substs);
+            }
+            ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
+                self.add_substs(substs);
+            }
+            ty::PredicateKind::ConstEquate(expected, found) => {
+                self.add_const(expected);
+                self.add_const(found);
+            }
+        }
+    }
+
     fn add_ty(&mut self, ty: Ty<'_>) {
         self.add_flags(ty.flags);
         self.add_exclusive_binder(ty.outer_exclusive_binder);
@@ -189,13 +253,13 @@ impl FlagComputation {
         computation.add_tys(fn_sig.skip_binder().inputs());
         computation.add_ty(fn_sig.skip_binder().output());
 
-        self.add_bound_computation(&computation);
+        self.add_bound_computation(computation);
     }
 
     fn add_region(&mut self, r: ty::Region<'_>) {
         self.add_flags(r.type_flags());
         if let ty::ReLateBound(debruijn, _) = *r {
-            self.add_binder(debruijn);
+            self.add_bound_var(debruijn);
         }
     }
 
@@ -214,7 +278,7 @@ impl FlagComputation {
                 }
             }
             ty::ConstKind::Bound(debruijn, _) => {
-                self.add_binder(debruijn);
+                self.add_bound_var(debruijn);
             }
             ty::ConstKind::Param(_) => {
                 self.add_flags(TypeFlags::HAS_CT_PARAM);
diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs
index 24dbf7b8c46..2d25c7c6ac9 100644
--- a/src/librustc_middle/ty/fold.rs
+++ b/src/librustc_middle/ty/fold.rs
@@ -31,6 +31,7 @@
 //! These methods return true to indicate that the visitor has found what it is
 //! looking for, and does not need to visit anything else.
 
+use crate::ty::structural_impls::PredicateVisitor;
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -908,6 +909,12 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
     }
 }
 
+impl<'tcx> PredicateVisitor<'tcx> for HasEscapingVarsVisitor {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+        predicate.inner.outer_exclusive_binder > self.outer_index
+    }
+}
+
 // FIXME: Optimize for checking for infer flags
 struct HasTypeFlagsVisitor {
     flags: ty::TypeFlags,
@@ -932,6 +939,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     }
 }
 
+impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+        debug!(
+            "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+            predicate, predicate.inner.flags, self.flags
+        );
+        predicate.inner.flags.intersects(self.flags)
+    }
+}
 /// Collects all the late-bound regions at the innermost binding level
 /// into a hash set.
 struct LateBoundRegionsCollector {
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 56fb3b58d3f..6b7940ed7ab 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -627,7 +627,7 @@ impl<'tcx> Hash for TyS<'tcx> {
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         let ty::TyS {
             ref kind,
@@ -1001,16 +1001,35 @@ impl<'tcx> GenericPredicates<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)]
-#[derive(HashStable)]
+#[derive(Debug)]
+crate struct PredicateInner<'tcx> {
+    kind: PredicateKind<'tcx>,
+    flags: TypeFlags,
+    /// See the comment for the corresponding field of [TyS].
+    outer_exclusive_binder: ty::DebruijnIndex,
+}
+
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PredicateInner<'_>, 40);
+
+#[derive(Clone, Copy, Lift)]
 pub struct Predicate<'tcx> {
-    kind: &'tcx PredicateKind<'tcx>,
+    inner: &'tcx PredicateInner<'tcx>,
 }
 
+impl rustc_serialize::UseSpecializedEncodable for Predicate<'_> {}
+impl rustc_serialize::UseSpecializedDecodable for Predicate<'_> {}
+
 impl<'tcx> PartialEq for Predicate<'tcx> {
     fn eq(&self, other: &Self) -> bool {
         // `self.kind` is always interned.
-        ptr::eq(self.kind, other.kind)
+        ptr::eq(self.inner, other.inner)
+    }
+}
+
+impl Hash for Predicate<'_> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        (self.inner as *const PredicateInner<'_>).hash(s)
     }
 }
 
@@ -1019,7 +1038,22 @@ impl<'tcx> Eq for Predicate<'tcx> {}
 impl<'tcx> Predicate<'tcx> {
     #[inline(always)]
     pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
-        self.kind
+        &self.inner.kind
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        let PredicateInner {
+            ref kind,
+
+            // The other fields just provide fast access to information that is
+            // also contained in `kind`, so no need to hash them.
+            flags: _,
+            outer_exclusive_binder: _,
+        } = self.inner;
+
+        kind.hash_stable(hcx, hasher);
     }
 }
 
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index f04d31601ea..f736037b5c1 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -987,12 +987,34 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let new = ty::PredicateKind::super_fold_with(self.kind, folder);
-        if new != *self.kind { folder.tcx().mk_predicate(new) } else { *self }
+        let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder);
+        if new != self.inner.kind { folder.tcx().mk_predicate(new) } else { *self }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        ty::PredicateKind::super_visit_with(self.kind, visitor)
+        ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_predicate(*self)
+    }
+
+    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.inner.outer_exclusive_binder > binder
+    }
+
+    fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
+        self.inner.flags.intersects(flags)
+    }
+}
+
+pub(super) trait PredicateVisitor<'tcx>: TypeVisitor<'tcx> {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool;
+}
+
+impl<T: TypeVisitor<'tcx>> PredicateVisitor<'tcx> for T {
+    default fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+        predicate.super_visit_with(self)
     }
 }