From 925ec0d3c77601ebfa32b148393a5192943c2ff1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jan 2022 17:00:16 +1100 Subject: [PATCH] Overhaul `PredicateInner` and `Predicate`. Specifically, change `Ty` from this: ``` pub struct Predicate<'tcx> { inner: &'tcx PredicateInner<'tcx> } ``` to this: ``` pub struct Predicate<'tcx>(&'tcx Interned>) ``` where `PredicateInner` is renamed as `PredicateS`. This (plus a few other minor changes) makes the parallels with `Ty` and `TyS` much clearer, and makes the uniqueness more explicit. --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 48 ++++++++-------- compiler/rustc_middle/src/ty/fold.rs | 8 ++- compiler/rustc_middle/src/ty/mod.rs | 57 +++++++++---------- .../rustc_middle/src/ty/structural_impls.rs | 8 +-- .../rustc_trait_selection/src/traits/wf.rs | 4 +- .../src/normalize_erasing_regions.rs | 4 +- .../rustc_typeck/src/check/method/suggest.rs | 6 +- 8 files changed, 68 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9caf77532a9..14655a0d00c 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -88,7 +88,7 @@ macro_rules! arena_types { // Interned types [] tys: rustc_middle::ty::TyS<'tcx>, - [] predicates: rustc_middle::ty::PredicateInner<'tcx>, + [] predicates: rustc_middle::ty::PredicateS<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e65a938d647..d9435517991 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -20,7 +20,7 @@ use crate::ty::{ self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst, - ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, + ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, }; use rustc_ast as ast; @@ -107,7 +107,7 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind>, poly_existential_predicates: InternedSet<'tcx, List>>>, - predicate: InternedSet<'tcx, PredicateInner<'tcx>>, + predicate: InternedSet<'tcx, PredicateS<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, @@ -170,23 +170,22 @@ impl<'tcx> CtxtInterners<'tcx> { } #[inline(never)] - fn intern_predicate( - &self, - kind: Binder<'tcx, PredicateKind<'tcx>>, - ) -> &'tcx PredicateInner<'tcx> { - self.predicate - .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_predicate(kind); + fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { + Predicate(Interned::new_unchecked( + 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, - }; + let predicate_struct = PredicateS { + kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; - InternedInSet(self.arena.alloc(predicate_struct)) - }) - .0 + InternedInSet(self.arena.alloc(predicate_struct)) + }) + .0, + )) } } @@ -1684,7 +1683,7 @@ nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift_old! {region; Region<'a> => Region<'tcx>} nop_lift_old! {const_; &'a Const<'a> => &'tcx Const<'tcx>} nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation} -nop_lift_old! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} +nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>} @@ -2040,23 +2039,23 @@ impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> { } } -impl<'tcx> Borrow>> for InternedInSet<'tcx, PredicateInner<'tcx>> { +impl<'tcx> Borrow>> for InternedInSet<'tcx, PredicateS<'tcx>> { fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { &self.0.kind } } -impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateInner<'tcx>> { - fn eq(&self, other: &InternedInSet<'tcx, PredicateInner<'tcx>>) -> bool { +impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> { + fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. self.0.kind == other.0.kind } } -impl<'tcx> Eq for InternedInSet<'tcx, PredicateInner<'tcx>> {} +impl<'tcx> Eq for InternedInSet<'tcx, PredicateS<'tcx>> {} -impl<'tcx> Hash for InternedInSet<'tcx, PredicateInner<'tcx>> { +impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> { fn hash(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0.kind.hash(s) @@ -2237,8 +2236,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { - let inner = self.interners.intern_predicate(binder); - Predicate { inner } + self.interners.intern_predicate(binder) } #[inline] diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index c13982d69b5..f55e8bbddaa 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1181,7 +1181,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { #[inline] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { - if predicate.inner.outer_exclusive_binder > self.outer_index { + if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE @@ -1263,9 +1263,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", - predicate, predicate.inner.flags, self.flags + predicate, + predicate.flags(), + self.flags ); - if predicate.inner.flags.intersects(self.flags) { + if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 812c5018459..78bf9b81eeb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -43,9 +43,9 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span}; use rustc_target::abi::Align; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::ops::ControlFlow; -use std::{fmt, ptr, str}; +use std::{fmt, str}; pub use crate::ty::diagnostics::*; pub use rustc_type_ir::InferTy::*; @@ -466,51 +466,50 @@ impl ty::EarlyBoundRegion { } } +/// Represents a predicate. +/// +/// See comments on `TyS`, which apply here too (albeit for +/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`). #[derive(Debug)] -crate struct PredicateInner<'tcx> { +crate struct PredicateS<'tcx> { kind: Binder<'tcx, PredicateKind<'tcx>>, flags: TypeFlags, /// See the comment for the corresponding field of [TyS]. outer_exclusive_binder: ty::DebruijnIndex, } +// This type is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateInner<'_>, 56); +static_assert_size!(PredicateS<'_>, 56); -#[derive(Clone, Copy, Lift)] -pub struct Predicate<'tcx> { - inner: &'tcx PredicateInner<'tcx>, -} - -impl<'tcx> PartialEq for Predicate<'tcx> { - fn eq(&self, other: &Self) -> bool { - // `self.kind` is always interned. - ptr::eq(self.inner, other.inner) - } -} - -impl Hash for Predicate<'_> { - fn hash(&self, s: &mut H) { - (self.inner as *const PredicateInner<'_>).hash(s) - } -} - -impl<'tcx> Eq for Predicate<'tcx> {} +/// Use this rather than `PredicateS`, whenever possible. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>); impl<'tcx> Predicate<'tcx> { /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. #[inline] pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { - self.inner.kind + self.0.kind + } + + #[inline(always)] + pub fn flags(self) -> TypeFlags { + self.0.flags + } + + #[inline(always)] + pub fn outer_exclusive_binder(self) -> DebruijnIndex { + self.0.outer_exclusive_binder } /// Flips the polarity of a Predicate. /// /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. - pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option> { + pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option> { let kind = self - .inner - .kind + .kind() .map_bound(|kind| match kind { PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => { Some(PredicateKind::Trait(TraitPredicate { @@ -530,14 +529,14 @@ impl<'tcx> Predicate<'tcx> { impl<'a, 'tcx> HashStable> for Predicate<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let PredicateInner { + let PredicateS { 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; + } = self.0.0; kind.hash_stable(hcx, hasher); } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index ddd102695bd..f59038569e1 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -1112,12 +1112,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { self, folder: &mut F, ) -> Result { - let new = self.inner.kind.try_fold_with(folder)?; + let new = self.kind().try_fold_with(folder)?; Ok(folder.tcx().reuse_or_mk_predicate(self, new)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.inner.kind.visit_with(visitor) + self.kind().visit_with(visitor) } fn visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -1125,11 +1125,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { } fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.inner.outer_exclusive_binder > binder + self.outer_exclusive_binder() > binder } fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { - self.inner.flags.intersects(flags) + self.flags().intersects(flags) } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 493cb199f11..403fabe0a90 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -198,7 +198,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( trait_ref: &ty::TraitRef<'tcx>, item: Option<&hir::Item<'tcx>>, cause: &mut traits::ObligationCause<'tcx>, - pred: &ty::Predicate<'tcx>, + pred: ty::Predicate<'tcx>, ) { debug!( "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", @@ -319,7 +319,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { trait_ref, item, &mut cause, - &obligation.predicate, + obligation.predicate, ); traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate) }; diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 46c2f7e4cf2..a4aa965ec95 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -39,7 +39,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + // always only region relations, and we are about to // erase those anyway: debug_assert_eq!( - normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)), + normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), None, ); @@ -57,7 +57,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + }) } -fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool { +fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { match p.kind().skip_binder() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, ty::PredicateKind::Trait(..) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 06fcad25d3c..4bef34eb77e 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -703,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut bound_spans = vec![]; let mut collect_type_param_suggestions = - |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| { + |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| { // We don't care about regions here, so it's fine to skip the binder here. if let (ty::Param(_), ty::PredicateKind::Trait(p)) = (self_ty.kind(), parent_pred.kind().skip_binder()) @@ -892,7 +892,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred)) .filter_map(|(pred, parent_pred, _cause)| { format_pred(*pred).map(|(p, self_ty)| { - collect_type_param_suggestions(self_ty, pred, &p); + collect_type_param_suggestions(self_ty, *pred, &p); match parent_pred { None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { @@ -900,7 +900,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some((parent_p, _)) => { collect_type_param_suggestions( self_ty, - parent_pred, + *parent_pred, &p, ); format!("`{}`\nwhich is required by `{}`", p, parent_p)