@@ -40,6 +40,7 @@ use rustc_hir::Node;
4040use rustc_index:: vec:: IndexVec ;
4141use rustc_macros:: HashStable ;
4242use rustc_query_system:: ich:: StableHashingContext ;
43+ use rustc_serialize:: { Decodable , Encodable } ;
4344use rustc_span:: hygiene:: MacroKind ;
4445use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
4546use rustc_span:: { ExpnId , Span } ;
@@ -49,6 +50,9 @@ pub use vtable::*;
4950
5051use std:: fmt:: Debug ;
5152use std:: hash:: { Hash , Hasher } ;
53+ use std:: marker:: PhantomData ;
54+ use std:: mem;
55+ use std:: num:: NonZeroUsize ;
5256use std:: ops:: ControlFlow ;
5357use std:: { fmt, str} ;
5458
@@ -902,42 +906,122 @@ pub struct CoercePredicate<'tcx> {
902906}
903907pub type PolyCoercePredicate < ' tcx > = ty:: Binder < ' tcx , CoercePredicate < ' tcx > > ;
904908
905- #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash , PartialOrd , Ord , TyEncodable , TyDecodable ) ]
906- #[ derive( HashStable , TypeFoldable , TypeVisitable ) ]
907- pub enum Term < ' tcx > {
908- Ty ( Ty < ' tcx > ) ,
909- Const ( Const < ' tcx > ) ,
909+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
910+ pub struct Term < ' tcx > {
911+ ptr : NonZeroUsize ,
912+ marker : PhantomData < ( Ty < ' tcx > , Const < ' tcx > ) > ,
910913}
911914
912915impl < ' tcx > From < Ty < ' tcx > > for Term < ' tcx > {
913916 fn from ( ty : Ty < ' tcx > ) -> Self {
914- Term :: Ty ( ty)
917+ TermKind :: Ty ( ty) . pack ( )
915918 }
916919}
917920
918921impl < ' tcx > From < Const < ' tcx > > for Term < ' tcx > {
919922 fn from ( c : Const < ' tcx > ) -> Self {
920- Term :: Const ( c)
923+ TermKind :: Const ( c) . pack ( )
924+ }
925+ }
926+
927+ impl < ' a , ' tcx > HashStable < StableHashingContext < ' a > > for Term < ' tcx > {
928+ fn hash_stable ( & self , hcx : & mut StableHashingContext < ' a > , hasher : & mut StableHasher ) {
929+ self . unpack ( ) . hash_stable ( hcx, hasher) ;
930+ }
931+ }
932+
933+ impl < ' tcx > TypeFoldable < ' tcx > for Term < ' tcx > {
934+ fn try_fold_with < F : FallibleTypeFolder < ' tcx > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
935+ Ok ( self . unpack ( ) . try_fold_with ( folder) ?. pack ( ) )
936+ }
937+ }
938+
939+ impl < ' tcx > TypeVisitable < ' tcx > for Term < ' tcx > {
940+ fn visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > {
941+ self . unpack ( ) . visit_with ( visitor)
942+ }
943+ }
944+
945+ impl < ' tcx , E : TyEncoder < I = TyCtxt < ' tcx > > > Encodable < E > for Term < ' tcx > {
946+ fn encode ( & self , e : & mut E ) {
947+ self . unpack ( ) . encode ( e)
948+ }
949+ }
950+
951+ impl < ' tcx , D : TyDecoder < I = TyCtxt < ' tcx > > > Decodable < D > for Term < ' tcx > {
952+ fn decode ( d : & mut D ) -> Self {
953+ let res: TermKind < ' tcx > = Decodable :: decode ( d) ;
954+ res. pack ( )
921955 }
922956}
923957
924958impl < ' tcx > Term < ' tcx > {
959+ #[ inline]
960+ pub fn unpack ( self ) -> TermKind < ' tcx > {
961+ let ptr = self . ptr . get ( ) ;
962+ // SAFETY: use of `Interned::new_unchecked` here is ok because these
963+ // pointers were originally created from `Interned` types in `pack()`,
964+ // and this is just going in the other direction.
965+ unsafe {
966+ match ptr & TAG_MASK {
967+ TYPE_TAG => TermKind :: Ty ( Ty ( Interned :: new_unchecked (
968+ & * ( ( ptr & !TAG_MASK ) as * const WithStableHash < ty:: TyS < ' tcx > > ) ,
969+ ) ) ) ,
970+ CONST_TAG => TermKind :: Const ( ty:: Const ( Interned :: new_unchecked (
971+ & * ( ( ptr & !TAG_MASK ) as * const ty:: ConstS < ' tcx > ) ,
972+ ) ) ) ,
973+ _ => core:: intrinsics:: unreachable ( ) ,
974+ }
975+ }
976+ }
977+
925978 pub fn ty ( & self ) -> Option < Ty < ' tcx > > {
926- if let Term :: Ty ( ty) = self { Some ( * ty) } else { None }
979+ if let TermKind :: Ty ( ty) = self . unpack ( ) { Some ( ty) } else { None }
927980 }
928981
929982 pub fn ct ( & self ) -> Option < Const < ' tcx > > {
930- if let Term :: Const ( c) = self { Some ( * c) } else { None }
983+ if let TermKind :: Const ( c) = self . unpack ( ) { Some ( c) } else { None }
931984 }
932985
933986 pub fn into_arg ( self ) -> GenericArg < ' tcx > {
934- match self {
935- Term :: Ty ( ty) => ty. into ( ) ,
936- Term :: Const ( c) => c. into ( ) ,
987+ match self . unpack ( ) {
988+ TermKind :: Ty ( ty) => ty. into ( ) ,
989+ TermKind :: Const ( c) => c. into ( ) ,
937990 }
938991 }
939992}
940993
994+ const TAG_MASK : usize = 0b11 ;
995+ const TYPE_TAG : usize = 0b00 ;
996+ const CONST_TAG : usize = 0b01 ;
997+
998+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash , PartialOrd , Ord , TyEncodable , TyDecodable ) ]
999+ #[ derive( HashStable , TypeFoldable , TypeVisitable ) ]
1000+ pub enum TermKind < ' tcx > {
1001+ Ty ( Ty < ' tcx > ) ,
1002+ Const ( Const < ' tcx > ) ,
1003+ }
1004+
1005+ impl < ' tcx > TermKind < ' tcx > {
1006+ #[ inline]
1007+ fn pack ( self ) -> Term < ' tcx > {
1008+ let ( tag, ptr) = match self {
1009+ TermKind :: Ty ( ty) => {
1010+ // Ensure we can use the tag bits.
1011+ assert_eq ! ( mem:: align_of_val( & * ty. 0.0 ) & TAG_MASK , 0 ) ;
1012+ ( TYPE_TAG , ty. 0 . 0 as * const WithStableHash < ty:: TyS < ' tcx > > as usize )
1013+ }
1014+ TermKind :: Const ( ct) => {
1015+ // Ensure we can use the tag bits.
1016+ assert_eq ! ( mem:: align_of_val( & * ct. 0.0 ) & TAG_MASK , 0 ) ;
1017+ ( CONST_TAG , ct. 0 . 0 as * const ty:: ConstS < ' tcx > as usize )
1018+ }
1019+ } ;
1020+
1021+ Term { ptr : unsafe { NonZeroUsize :: new_unchecked ( ptr | tag) } , marker : PhantomData }
1022+ }
1023+ }
1024+
9411025/// This kind of predicate has no *direct* correspondent in the
9421026/// syntax, but it roughly corresponds to the syntactic forms:
9431027///
@@ -2528,7 +2612,7 @@ mod size_asserts {
25282612 use super :: * ;
25292613 use rustc_data_structures:: static_assert_size;
25302614 // These are in alphabetical order, which is easy to maintain.
2531- static_assert_size ! ( PredicateS <' _>, 56 ) ;
2615+ static_assert_size ! ( PredicateS <' _>, 48 ) ;
25322616 static_assert_size ! ( TyS <' _>, 40 ) ;
25332617 static_assert_size ! ( WithStableHash <TyS <' _>>, 56 ) ;
25342618}
0 commit comments