@@ -23,9 +23,7 @@ use rustc_span::{Span, DUMMY_SP};
2323use smallvec:: SmallVec ;
2424
2525use std:: borrow:: Cow ;
26- use std:: fmt;
2726use std:: hash:: { Hash , Hasher } ;
28- use std:: ops:: Deref ;
2927
3028pub use self :: select:: { EvaluationCache , EvaluationResult , OverflowError , SelectionCache } ;
3129
@@ -80,38 +78,14 @@ pub enum Reveal {
8078
8179/// The reason why we incurred this obligation; used for error reporting.
8280///
83- /// As the happy path does not care about this struct, storing this on the heap
84- /// ends up increasing performance.
81+ /// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the
82+ /// best trade-off between keeping the type small (which makes copies cheaper)
83+ /// while not doing too many heap allocations.
8584///
8685/// We do not want to intern this as there are a lot of obligation causes which
8786/// only live for a short period of time.
88- #[ derive( Clone , PartialEq , Eq , Hash , Lift ) ]
89- pub struct ObligationCause < ' tcx > {
90- /// `None` for `ObligationCause::dummy`, `Some` otherwise.
91- data : Option < Lrc < ObligationCauseData < ' tcx > > > ,
92- }
93-
94- const DUMMY_OBLIGATION_CAUSE_DATA : ObligationCauseData < ' static > =
95- ObligationCauseData { span : DUMMY_SP , body_id : hir:: CRATE_HIR_ID , code : MiscObligation } ;
96-
97- // Correctly format `ObligationCause::dummy`.
98- impl < ' tcx > fmt:: Debug for ObligationCause < ' tcx > {
99- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
100- ObligationCauseData :: fmt ( self , f)
101- }
102- }
103-
104- impl < ' tcx > Deref for ObligationCause < ' tcx > {
105- type Target = ObligationCauseData < ' tcx > ;
106-
107- #[ inline( always) ]
108- fn deref ( & self ) -> & Self :: Target {
109- self . data . as_deref ( ) . unwrap_or ( & DUMMY_OBLIGATION_CAUSE_DATA )
110- }
111- }
112-
11387#[ derive( Clone , Debug , PartialEq , Eq , Lift ) ]
114- pub struct ObligationCauseData < ' tcx > {
88+ pub struct ObligationCause < ' tcx > {
11589 pub span : Span ,
11690
11791 /// The ID of the fn body that triggered this obligation. This is
@@ -122,46 +96,58 @@ pub struct ObligationCauseData<'tcx> {
12296 /// information.
12397 pub body_id : hir:: HirId ,
12498
125- pub code : ObligationCauseCode < ' tcx > ,
99+ /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
100+ /// the time). `Some` otherwise.
101+ code : Option < Lrc < ObligationCauseCode < ' tcx > > > ,
126102}
127103
128- impl Hash for ObligationCauseData < ' _ > {
104+ // This custom hash function speeds up hashing for `Obligation` deduplication
105+ // greatly by skipping the `code` field, which can be large and complex. That
106+ // shouldn't affect hash quality much since there are several other fields in
107+ // `Obligation` which should be unique enough, especially the predicate itself
108+ // which is hashed as an interned pointer. See #90996.
109+ impl Hash for ObligationCause < ' _ > {
129110 fn hash < H : Hasher > ( & self , state : & mut H ) {
130111 self . body_id . hash ( state) ;
131112 self . span . hash ( state) ;
132- std:: mem:: discriminant ( & self . code ) . hash ( state) ;
133113 }
134114}
135115
116+ const MISC_OBLIGATION_CAUSE_CODE : ObligationCauseCode < ' static > = MiscObligation ;
117+
136118impl < ' tcx > ObligationCause < ' tcx > {
137119 #[ inline]
138120 pub fn new (
139121 span : Span ,
140122 body_id : hir:: HirId ,
141123 code : ObligationCauseCode < ' tcx > ,
142124 ) -> ObligationCause < ' tcx > {
143- ObligationCause { data : Some ( Lrc :: new ( ObligationCauseData { span, body_id, code } ) ) }
125+ ObligationCause {
126+ span,
127+ body_id,
128+ code : if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some ( Lrc :: new ( code) ) } ,
129+ }
144130 }
145131
146132 pub fn misc ( span : Span , body_id : hir:: HirId ) -> ObligationCause < ' tcx > {
147133 ObligationCause :: new ( span, body_id, MiscObligation )
148134 }
149135
150- pub fn dummy_with_span ( span : Span ) -> ObligationCause < ' tcx > {
151- ObligationCause :: new ( span, hir:: CRATE_HIR_ID , MiscObligation )
152- }
153-
154136 #[ inline( always) ]
155137 pub fn dummy ( ) -> ObligationCause < ' tcx > {
156- ObligationCause { data : None }
138+ ObligationCause { span : DUMMY_SP , body_id : hir:: CRATE_HIR_ID , code : None }
139+ }
140+
141+ pub fn dummy_with_span ( span : Span ) -> ObligationCause < ' tcx > {
142+ ObligationCause { span, body_id : hir:: CRATE_HIR_ID , code : None }
157143 }
158144
159- pub fn make_mut ( & mut self ) -> & mut ObligationCauseData < ' tcx > {
160- Lrc :: make_mut ( self . data . get_or_insert_with ( || Lrc :: new ( DUMMY_OBLIGATION_CAUSE_DATA ) ) )
145+ pub fn make_mut_code ( & mut self ) -> & mut ObligationCauseCode < ' tcx > {
146+ Lrc :: make_mut ( self . code . get_or_insert_with ( || Lrc :: new ( MISC_OBLIGATION_CAUSE_CODE ) ) )
161147 }
162148
163149 pub fn span ( & self , tcx : TyCtxt < ' tcx > ) -> Span {
164- match self . code {
150+ match * self . code ( ) {
165151 ObligationCauseCode :: CompareImplMethodObligation { .. }
166152 | ObligationCauseCode :: MainFunctionType
167153 | ObligationCauseCode :: StartFunctionType => {
@@ -174,6 +160,18 @@ impl<'tcx> ObligationCause<'tcx> {
174160 _ => self . span ,
175161 }
176162 }
163+
164+ #[ inline]
165+ pub fn code ( & self ) -> & ObligationCauseCode < ' tcx > {
166+ self . code . as_deref ( ) . unwrap_or ( & MISC_OBLIGATION_CAUSE_CODE )
167+ }
168+
169+ pub fn clone_code ( & self ) -> Lrc < ObligationCauseCode < ' tcx > > {
170+ match & self . code {
171+ Some ( code) => code. clone ( ) ,
172+ None => Lrc :: new ( MISC_OBLIGATION_CAUSE_CODE ) ,
173+ }
174+ }
177175}
178176
179177#[ derive( Clone , Debug , PartialEq , Eq , Hash , Lift ) ]
0 commit comments