1
+ // ignore-tidy-filelength
2
+
1
3
pub use self :: fold:: { TypeFoldable , TypeVisitor } ;
2
4
pub use self :: AssocItemContainer :: * ;
3
5
pub use self :: BorrowKind :: * ;
@@ -45,6 +47,7 @@ use std::cell::RefCell;
45
47
use std:: cmp:: Ordering ;
46
48
use std:: fmt;
47
49
use std:: hash:: { Hash , Hasher } ;
50
+ use std:: marker:: PhantomData ;
48
51
use std:: ops:: Range ;
49
52
use std:: ptr;
50
53
@@ -1571,24 +1574,93 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
1571
1574
/// When type checking, we use the `ParamEnv` to track
1572
1575
/// details about the set of where-clauses that are in scope at this
1573
1576
/// particular point.
1574
- #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash , HashStable , TypeFoldable ) ]
1577
+ #[ derive( Copy , Clone ) ]
1575
1578
pub 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
+
1576
1591
/// `Obligation`s that the caller must satisfy. This is basically
1577
1592
/// the set of bounds on the in-scope type parameters, translated
1578
1593
/// 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 > > > ,
1580
1598
1581
1599
/// 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 > ,
1585
1605
1586
1606
/// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
1587
1607
/// register that `def_id` (useful for transitioning to the chalk trait
1588
1608
/// solver).
1589
1609
pub def_id : Option < DefId > ,
1590
1610
}
1591
1611
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
+
1592
1664
impl < ' tcx > ParamEnv < ' tcx > {
1593
1665
/// Construct a trait environment suitable for contexts where
1594
1666
/// there are no where-clauses in scope. Hidden types (like `impl
@@ -1599,6 +1671,17 @@ impl<'tcx> ParamEnv<'tcx> {
1599
1671
Self :: new ( List :: empty ( ) , Reveal :: UserFacing , None )
1600
1672
}
1601
1673
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
+
1602
1685
/// Construct a trait environment with no where-clauses in scope
1603
1686
/// where the values of all `impl Trait` and other hidden types
1604
1687
/// are revealed. This is suitable for monomorphized, post-typeck
@@ -1618,7 +1701,25 @@ impl<'tcx> ParamEnv<'tcx> {
1618
1701
reveal : Reveal ,
1619
1702
def_id : Option < DefId > ,
1620
1703
) -> 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
1622
1723
}
1623
1724
1624
1725
/// Returns a new parameter environment with the same clauses, but
@@ -1627,13 +1728,14 @@ impl<'tcx> ParamEnv<'tcx> {
1627
1728
/// the desired behavior during codegen and certain other special
1628
1729
/// contexts; normally though we want to use `Reveal::UserFacing`,
1629
1730
/// 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
1632
1734
}
1633
1735
1634
1736
/// Returns this same environment but with no caller bounds.
1635
1737
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 )
1637
1739
}
1638
1740
1639
1741
/// Creates a suitable environment in which to perform trait
@@ -1649,7 +1751,7 @@ impl<'tcx> ParamEnv<'tcx> {
1649
1751
/// satisfiable. We generally want to behave as if they were true,
1650
1752
/// although the surrounding function is never reachable.
1651
1753
pub fn and < T : TypeFoldable < ' tcx > > ( self , value : T ) -> ParamEnvAnd < ' tcx , T > {
1652
- match self . reveal {
1754
+ match self . reveal ( ) {
1653
1755
Reveal :: UserFacing => ParamEnvAnd { param_env : self , value } ,
1654
1756
1655
1757
Reveal :: All => {
0 commit comments