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>, region: InternedSet<'tcx, RegionKind>, existential_predicates: InternedSet<'tcx, List>>, - predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>, + predicate: InternedSet<'tcx, PredicateInner<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, @@ -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> for Interned<'tcx, TyS<'tcx>> { &self.0.kind } } +// N.B., an `Interned` 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(&self, s: &mut H) { + self.0.kind.hash(s) + } +} + +impl<'tcx> Borrow> for Interned<'tcx, PredicateInner<'tcx>> { + fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> { + &self.0.kind + } +} // N.B., an `Interned>` compares and hashes as its elements. impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List> { @@ -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> for ty::TyS<'tcx> { +impl<'a, 'tcx> HashStable> 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)] -pub struct Predicate<'tcx> { - kind: &'tcx PredicateKind<'tcx>, +#[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> { + 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(&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> 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>(&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>(&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>(&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> PredicateVisitor<'tcx> for T { + default fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { + predicate.super_visit_with(self) } }