Skip to content

Commit

Permalink
Auto merge of #73978 - Mark-Simulacrum:shrink-paramenv, r=nnethercote
Browse files Browse the repository at this point in the history
Shrink ParamEnv to 16 bytes

r? @nnethercote

x.py check passes but I haven't tried running perf or tests
  • Loading branch information
bors committed Jul 6, 2020
2 parents 0c03aee + 8512d2e commit 8981dbb
Show file tree
Hide file tree
Showing 24 changed files with 188 additions and 83 deletions.
2 changes: 1 addition & 1 deletion src/librustc_infer/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
debug!("explicit_outlives_bounds()");
param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate.kind() {
param_env.caller_bounds().into_iter().filter_map(move |predicate| match predicate.kind() {
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_infer/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// dubious for projections, but it will work for simple cases
// like `T` and `T::Item`. It may not work as well for things
// like `<T as Foo<'a>>::Item`.
let c_b = self.param_env.caller_bounds;
let c_b = self.param_env.caller_bounds();
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter());

// Next, collect regions we scraped from the well-formedness
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_infer/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;

// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PredicateObligation<'_>, 48);
static_assert_size!(PredicateObligation<'_>, 40);

pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Ignore layouts that are done with non-empty environments or
// non-monomorphic layouts, as the user only wants to see the stuff
// resulting from the final codegen session.
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds.is_empty() {
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
return;
}

Expand Down
122 changes: 112 additions & 10 deletions src/librustc_middle/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore-tidy-filelength

pub use self::fold::{TypeFoldable, TypeVisitor};
pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*;
Expand Down Expand Up @@ -45,6 +47,7 @@ use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::Range;
use std::ptr;

Expand Down Expand Up @@ -1571,24 +1574,93 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeFoldable)]
#[derive(Copy, Clone)]
pub struct ParamEnv<'tcx> {
// We pack the caller_bounds List pointer and a Reveal enum into this usize.
// Specifically, the low bit represents Reveal, with 0 meaning `UserFacing`
// and 1 meaning `All`. The rest is the pointer.
//
// This relies on the List<ty::Predicate<'tcx>> type having at least 2-byte
// alignment. Lists start with a usize and are repr(C) so this should be
// fine; there is a debug_assert in the constructor as well.
//
// Note that the choice of 0 for UserFacing is intentional -- since it is the
// first variant in Reveal this means that joining the pointer is a simple `or`.
packed_data: usize,

/// `Obligation`s that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated
/// into `Obligation`s, and elaborated and normalized.
pub caller_bounds: &'tcx List<ty::Predicate<'tcx>>,
///
/// Note: This is packed into the `packed_data` usize above, use the
/// `caller_bounds()` method to access it.
caller_bounds: PhantomData<&'tcx List<ty::Predicate<'tcx>>>,

/// Typically, this is `Reveal::UserFacing`, but during codegen we
/// want `Reveal::All` -- note that this is always paired with an
/// empty environment. To get that, use `ParamEnv::reveal()`.
pub reveal: traits::Reveal,
/// want `Reveal::All`.
///
/// Note: This is packed into the caller_bounds usize above, use the reveal()
/// method to access it.
reveal: PhantomData<traits::Reveal>,

/// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
/// register that `def_id` (useful for transitioning to the chalk trait
/// solver).
pub def_id: Option<DefId>,
}

impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ParamEnv")
.field("caller_bounds", &self.caller_bounds())
.field("reveal", &self.reveal())
.field("def_id", &self.def_id)
.finish()
}
}

impl<'tcx> Hash for ParamEnv<'tcx> {
fn hash<H: Hasher>(&self, state: &mut H) {
// List hashes as the raw pointer, so we can skip splitting into the
// pointer and the enum.
self.packed_data.hash(state);
self.def_id.hash(state);
}
}

impl<'tcx> PartialEq for ParamEnv<'tcx> {
fn eq(&self, other: &Self) -> bool {
self.caller_bounds() == other.caller_bounds()
&& self.reveal() == other.reveal()
&& self.def_id == other.def_id
}
}
impl<'tcx> Eq for ParamEnv<'tcx> {}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.caller_bounds().hash_stable(hcx, hasher);
self.reveal().hash_stable(hcx, hasher);
self.def_id.hash_stable(hcx, hasher);
}
}

impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
ParamEnv::new(
self.caller_bounds().fold_with(folder),
self.reveal().fold_with(folder),
self.def_id.fold_with(folder),
)
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.caller_bounds().visit_with(visitor)
|| self.reveal().visit_with(visitor)
|| self.def_id.visit_with(visitor)
}
}

impl<'tcx> ParamEnv<'tcx> {
/// Construct a trait environment suitable for contexts where
/// there are no where-clauses in scope. Hidden types (like `impl
Expand All @@ -1599,6 +1671,17 @@ impl<'tcx> ParamEnv<'tcx> {
Self::new(List::empty(), Reveal::UserFacing, None)
}

#[inline]
pub fn caller_bounds(self) -> &'tcx List<ty::Predicate<'tcx>> {
// mask out bottom bit
unsafe { &*((self.packed_data & (!1)) as *const _) }
}

#[inline]
pub fn reveal(self) -> traits::Reveal {
if self.packed_data & 1 == 0 { traits::Reveal::UserFacing } else { traits::Reveal::All }
}

/// Construct a trait environment with no where-clauses in scope
/// where the values of all `impl Trait` and other hidden types
/// are revealed. This is suitable for monomorphized, post-typeck
Expand All @@ -1618,7 +1701,25 @@ impl<'tcx> ParamEnv<'tcx> {
reveal: Reveal,
def_id: Option<DefId>,
) -> Self {
ty::ParamEnv { caller_bounds, reveal, def_id }
let packed_data = caller_bounds as *const _ as usize;
// Check that we can pack the reveal data into the pointer.
debug_assert!(packed_data & 1 == 0);
ty::ParamEnv {
packed_data: packed_data
| match reveal {
Reveal::UserFacing => 0,
Reveal::All => 1,
},
caller_bounds: PhantomData,
reveal: PhantomData,
def_id,
}
}

pub fn with_user_facing(mut self) -> Self {
// clear bottom bit
self.packed_data &= !1;
self
}

/// Returns a new parameter environment with the same clauses, but
Expand All @@ -1627,13 +1728,14 @@ impl<'tcx> ParamEnv<'tcx> {
/// the desired behavior during codegen and certain other special
/// contexts; normally though we want to use `Reveal::UserFacing`,
/// which is the default.
pub fn with_reveal_all(self) -> Self {
ty::ParamEnv { reveal: Reveal::All, ..self }
pub fn with_reveal_all(mut self) -> Self {
self.packed_data |= 1;
self
}

/// Returns this same environment but with no caller bounds.
pub fn without_caller_bounds(self) -> Self {
ty::ParamEnv { caller_bounds: List::empty(), ..self }
Self::new(List::empty(), self.reveal(), self.def_id)
}

/// Creates a suitable environment in which to perform trait
Expand All @@ -1649,7 +1751,7 @@ impl<'tcx> ParamEnv<'tcx> {
/// satisfiable. We generally want to behave as if they were true,
/// although the surrounding function is never reachable.
pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
match self.reveal {
match self.reveal() {
Reveal::UserFacing => ParamEnvAnd { param_env: self, value },

Reveal::All => {
Expand Down
7 changes: 2 additions & 5 deletions src/librustc_middle/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
type Lifted = ty::ParamEnv<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.caller_bounds).map(|caller_bounds| ty::ParamEnv {
reveal: self.reveal,
caller_bounds,
def_id: self.def_id,
})
tcx.lift(&self.caller_bounds())
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id))
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/librustc_mir/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ pub fn const_eval_validated_provider<'tcx>(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> {
// see comment in const_eval_raw_provider for what we're doing here
if key.param_env.reveal == Reveal::All {
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env.reveal = Reveal::UserFacing;
key.param_env = key.param_env.with_user_facing();
match tcx.const_eval_validated(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
Expand Down Expand Up @@ -267,9 +267,9 @@ pub fn const_eval_raw_provider<'tcx>(
// information being available.

// In case we fail in the `UserFacing` variant, we just do the real computation.
if key.param_env.reveal == Reveal::All {
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env.reveal = Reveal::UserFacing;
key.param_env = key.param_env.with_user_facing();
match tcx.const_eval_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
Expand Down Expand Up @@ -326,7 +326,7 @@ pub fn const_eval_raw_provider<'tcx>(
// this is `Reveal::UserFacing`, then it's expected that we could get a
// `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
// succeed or we'll report this error then.
if key.param_env.reveal == Reveal::All {
if key.param_env.reveal() == Reveal::All {
tcx.sess.delay_span_bug(
err.span,
&format!("static eval failure did not emit an error: {:#?}", v),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/util/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ where
let subpath = self.elaborator.field_subpath(variant_path, field);
let tcx = self.tcx();

assert_eq!(self.elaborator.param_env().reveal, Reveal::All);
assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
let field_ty =
tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs));
(tcx.mk_place_field(base_place, field, field_ty), subpath)
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trait_selection/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ impl AutoTraitFinder<'tcx> {
},
}));

let computed_preds = param_env.caller_bounds.iter();
let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds.iter().collect();
let computed_preds = param_env.caller_bounds().iter();
let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds().iter().collect();

let mut new_env = param_env;
let dummy_cause = ObligationCause::dummy();
Expand Down Expand Up @@ -368,12 +368,12 @@ impl AutoTraitFinder<'tcx> {
)
.map(|o| o.predicate);
new_env =
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal, None);
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None);
}

let final_user_env = ty::ParamEnv::new(
tcx.mk_predicates(user_computed_preds.into_iter()),
user_env.reveal,
user_env.reveal(),
None,
);
debug!(
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trait_selection/traits/chalk_fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ fn in_environment(

let environment = match obligation.param_env.def_id {
Some(def_id) => environment(infcx.tcx, def_id),
None if obligation.param_env.caller_bounds.is_empty() => ty::List::empty(),
None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(),
// FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
// and ui/generics/generic-static-methods
//_ => bug!("non-empty `ParamEnv` with no def-id"),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trait_selection/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub struct PendingPredicateObligation<'tcx> {

// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PendingPredicateObligation<'_>, 72);
static_assert_size!(PendingPredicateObligation<'_>, 64);

impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trait_selection/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,15 @@ pub fn normalize_param_env_or_error<'tcx>(
);

let mut predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.into_iter())
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
.map(|obligation| obligation.predicate)
.collect();

debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);

let elaborated_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal,
unnormalized_env.reveal(),
unnormalized_env.def_id,
);

Expand Down Expand Up @@ -361,7 +361,7 @@ pub fn normalize_param_env_or_error<'tcx>(
let outlives_env: Vec<_> =
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
let outlives_env =
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None);
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None);
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
Expand All @@ -383,7 +383,7 @@ pub fn normalize_param_env_or_error<'tcx>(
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal,
unnormalized_env.reveal(),
unnormalized_env.def_id,
)
}
Expand Down
12 changes: 7 additions & 5 deletions src/librustc_trait_selection/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ fn receiver_is_dispatchable<'tcx>(
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
// `U: ?Sized` is already implied here
let param_env = {
let mut param_env = tcx.param_env(method.def_id);
let param_env = tcx.param_env(method.def_id);

// Self: Unsize<U>
let unsize_predicate = ty::TraitRef {
Expand All @@ -656,15 +656,17 @@ fn receiver_is_dispatchable<'tcx>(
};

let caller_bounds: Vec<Predicate<'tcx>> = param_env
.caller_bounds
.caller_bounds()
.iter()
.chain(iter::once(unsize_predicate))
.chain(iter::once(trait_predicate))
.collect();

param_env.caller_bounds = tcx.intern_predicates(&caller_bounds);

param_env
ty::ParamEnv::new(
tcx.intern_predicates(&caller_bounds),
param_env.reveal(),
param_env.def_id,
)
};

// Receiver: DispatchFromDyn<Receiver[Self => U]>
Expand Down
Loading

0 comments on commit 8981dbb

Please sign in to comment.