-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shrink ParamEnv to 16 bytes #73978
Merged
Merged
Shrink ParamEnv to 16 bytes #73978
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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::*; | ||
|
@@ -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; | ||
|
||
|
@@ -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>>>, | ||
nnethercote marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// 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>, | ||
nnethercote marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// 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 | ||
|
@@ -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 | ||
|
@@ -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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: swap these arms so the 0 is first? |
||
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 | ||
|
@@ -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 | ||
|
@@ -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 => { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Late to the party, but maybe move all of the safety-critical parts of this into a
ty::param_env
module? That or we could try to build a bit-packed abstraction (sincety::GenericArg
does something similar), or look for one on crates.io and audit it.