1+ // ignore-tidy-filelength
2+
13pub use self :: fold:: { TypeFoldable , TypeVisitor } ;
24pub use self :: AssocItemContainer :: * ;
35pub use self :: BorrowKind :: * ;
@@ -45,6 +47,7 @@ use std::cell::RefCell;
4547use std:: cmp:: Ordering ;
4648use std:: fmt;
4749use std:: hash:: { Hash , Hasher } ;
50+ use std:: marker:: PhantomData ;
4851use std:: ops:: Range ;
4952use std:: ptr;
5053
@@ -1571,24 +1574,93 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
15711574/// When type checking, we use the `ParamEnv` to track
15721575/// details about the set of where-clauses that are in scope at this
15731576/// particular point.
1574- #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash , HashStable , TypeFoldable ) ]
1577+ #[ derive( Copy , Clone ) ]
15751578pub struct ParamEnv < ' tcx > {
1579+ // We pack the caller_bounds List pointer and a Reveal enum into this usize.
1580+ // Specifically, the low bit represents Reveal, with 0 meaning `UserFacing`
1581+ // and 1 meaning `All`. The rest is the pointer.
1582+ //
1583+ // This relies on the List<ty::Predicate<'tcx>> type having at least 2-byte
1584+ // alignment. Lists start with a usize and are repr(C) so this should be
1585+ // fine; there is a debug_assert in the constructor as well.
1586+ //
1587+ // Note that the choice of 0 for UserFacing is intentional -- since it is the
1588+ // first variant in Reveal this means that joining the pointer is a simple `or`.
1589+ packed_data : usize ,
1590+
15761591 /// `Obligation`s that the caller must satisfy. This is basically
15771592 /// the set of bounds on the in-scope type parameters, translated
15781593 /// into `Obligation`s, and elaborated and normalized.
1579- pub caller_bounds : & ' tcx List < ty:: Predicate < ' tcx > > ,
1594+ ///
1595+ /// Note: This is packed into the `packed_data` usize above, use the
1596+ /// `caller_bounds()` method to access it.
1597+ caller_bounds : PhantomData < & ' tcx List < ty:: Predicate < ' tcx > > > ,
15801598
15811599 /// Typically, this is `Reveal::UserFacing`, but during codegen we
1582- /// want `Reveal::All` -- note that this is always paired with an
1583- /// empty environment. To get that, use `ParamEnv::reveal()`.
1584- pub reveal : traits:: Reveal ,
1600+ /// want `Reveal::All`.
1601+ ///
1602+ /// Note: This is packed into the caller_bounds usize above, use the reveal()
1603+ /// method to access it.
1604+ reveal : PhantomData < traits:: Reveal > ,
15851605
15861606 /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
15871607 /// register that `def_id` (useful for transitioning to the chalk trait
15881608 /// solver).
15891609 pub def_id : Option < DefId > ,
15901610}
15911611
1612+ impl < ' tcx > fmt:: Debug for ParamEnv < ' tcx > {
1613+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1614+ f. debug_struct ( "ParamEnv" )
1615+ . field ( "caller_bounds" , & self . caller_bounds ( ) )
1616+ . field ( "reveal" , & self . reveal ( ) )
1617+ . field ( "def_id" , & self . def_id )
1618+ . finish ( )
1619+ }
1620+ }
1621+
1622+ impl < ' tcx > Hash for ParamEnv < ' tcx > {
1623+ fn hash < H : Hasher > ( & self , state : & mut H ) {
1624+ // List hashes as the raw pointer, so we can skip splitting into the
1625+ // pointer and the enum.
1626+ self . packed_data . hash ( state) ;
1627+ self . def_id . hash ( state) ;
1628+ }
1629+ }
1630+
1631+ impl < ' tcx > PartialEq for ParamEnv < ' tcx > {
1632+ fn eq ( & self , other : & Self ) -> bool {
1633+ self . caller_bounds ( ) == other. caller_bounds ( )
1634+ && self . reveal ( ) == other. reveal ( )
1635+ && self . def_id == other. def_id
1636+ }
1637+ }
1638+ impl < ' tcx > Eq for ParamEnv < ' tcx > { }
1639+
1640+ impl < ' a , ' tcx > HashStable < StableHashingContext < ' a > > for ParamEnv < ' tcx > {
1641+ fn hash_stable ( & self , hcx : & mut StableHashingContext < ' a > , hasher : & mut StableHasher ) {
1642+ self . caller_bounds ( ) . hash_stable ( hcx, hasher) ;
1643+ self . reveal ( ) . hash_stable ( hcx, hasher) ;
1644+ self . def_id . hash_stable ( hcx, hasher) ;
1645+ }
1646+ }
1647+
1648+ impl < ' tcx > TypeFoldable < ' tcx > for ParamEnv < ' tcx > {
1649+ fn super_fold_with < F : ty:: fold:: TypeFolder < ' tcx > > ( & self , folder : & mut F ) -> Self {
1650+ ParamEnv :: new (
1651+ self . caller_bounds ( ) . fold_with ( folder) ,
1652+ self . reveal ( ) . fold_with ( folder) ,
1653+ self . def_id . fold_with ( folder) ,
1654+ )
1655+ }
1656+
1657+ fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> bool {
1658+ self . caller_bounds ( ) . visit_with ( visitor)
1659+ || self . reveal ( ) . visit_with ( visitor)
1660+ || self . def_id . visit_with ( visitor)
1661+ }
1662+ }
1663+
15921664impl < ' tcx > ParamEnv < ' tcx > {
15931665 /// Construct a trait environment suitable for contexts where
15941666 /// there are no where-clauses in scope. Hidden types (like `impl
@@ -1599,6 +1671,17 @@ impl<'tcx> ParamEnv<'tcx> {
15991671 Self :: new ( List :: empty ( ) , Reveal :: UserFacing , None )
16001672 }
16011673
1674+ #[ inline]
1675+ pub fn caller_bounds ( self ) -> & ' tcx List < ty:: Predicate < ' tcx > > {
1676+ // mask out bottom bit
1677+ unsafe { & * ( ( self . packed_data & ( !1 ) ) as * const _ ) }
1678+ }
1679+
1680+ #[ inline]
1681+ pub fn reveal ( self ) -> traits:: Reveal {
1682+ if self . packed_data & 1 == 0 { traits:: Reveal :: UserFacing } else { traits:: Reveal :: All }
1683+ }
1684+
16021685 /// Construct a trait environment with no where-clauses in scope
16031686 /// where the values of all `impl Trait` and other hidden types
16041687 /// are revealed. This is suitable for monomorphized, post-typeck
@@ -1618,7 +1701,25 @@ impl<'tcx> ParamEnv<'tcx> {
16181701 reveal : Reveal ,
16191702 def_id : Option < DefId > ,
16201703 ) -> Self {
1621- ty:: ParamEnv { caller_bounds, reveal, def_id }
1704+ let packed_data = caller_bounds as * const _ as usize ;
1705+ // Check that we can pack the reveal data into the pointer.
1706+ debug_assert ! ( packed_data & 1 == 0 ) ;
1707+ ty:: ParamEnv {
1708+ packed_data : packed_data
1709+ | match reveal {
1710+ Reveal :: UserFacing => 0 ,
1711+ Reveal :: All => 1 ,
1712+ } ,
1713+ caller_bounds : PhantomData ,
1714+ reveal : PhantomData ,
1715+ def_id,
1716+ }
1717+ }
1718+
1719+ pub fn with_user_facing ( mut self ) -> Self {
1720+ // clear bottom bit
1721+ self . packed_data &= !1 ;
1722+ self
16221723 }
16231724
16241725 /// Returns a new parameter environment with the same clauses, but
@@ -1627,13 +1728,14 @@ impl<'tcx> ParamEnv<'tcx> {
16271728 /// the desired behavior during codegen and certain other special
16281729 /// contexts; normally though we want to use `Reveal::UserFacing`,
16291730 /// which is the default.
1630- pub fn with_reveal_all ( self ) -> Self {
1631- ty:: ParamEnv { reveal : Reveal :: All , ..self }
1731+ pub fn with_reveal_all ( mut self ) -> Self {
1732+ self . packed_data |= 1 ;
1733+ self
16321734 }
16331735
16341736 /// Returns this same environment but with no caller bounds.
16351737 pub fn without_caller_bounds ( self ) -> Self {
1636- ty :: ParamEnv { caller_bounds : List :: empty ( ) , .. self }
1738+ Self :: new ( List :: empty ( ) , self . reveal ( ) , self . def_id )
16371739 }
16381740
16391741 /// Creates a suitable environment in which to perform trait
@@ -1649,7 +1751,7 @@ impl<'tcx> ParamEnv<'tcx> {
16491751 /// satisfiable. We generally want to behave as if they were true,
16501752 /// although the surrounding function is never reachable.
16511753 pub fn and < T : TypeFoldable < ' tcx > > ( self , value : T ) -> ParamEnvAnd < ' tcx , T > {
1652- match self . reveal {
1754+ match self . reveal ( ) {
16531755 Reveal :: UserFacing => ParamEnvAnd { param_env : self , value } ,
16541756
16551757 Reveal :: All => {
0 commit comments