@@ -23,9 +23,7 @@ use rustc_span::{Span, DUMMY_SP};
23
23
use smallvec:: SmallVec ;
24
24
25
25
use std:: borrow:: Cow ;
26
- use std:: fmt;
27
26
use std:: hash:: { Hash , Hasher } ;
28
- use std:: ops:: Deref ;
29
27
30
28
pub use self :: select:: { EvaluationCache , EvaluationResult , OverflowError , SelectionCache } ;
31
29
@@ -80,38 +78,14 @@ pub enum Reveal {
80
78
81
79
/// The reason why we incurred this obligation; used for error reporting.
82
80
///
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.
85
84
///
86
85
/// We do not want to intern this as there are a lot of obligation causes which
87
86
/// 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
-
113
87
#[ derive( Clone , Debug , PartialEq , Eq , Lift ) ]
114
- pub struct ObligationCauseData < ' tcx > {
88
+ pub struct ObligationCause < ' tcx > {
115
89
pub span : Span ,
116
90
117
91
/// The ID of the fn body that triggered this obligation. This is
@@ -122,46 +96,58 @@ pub struct ObligationCauseData<'tcx> {
122
96
/// information.
123
97
pub body_id : hir:: HirId ,
124
98
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 > > > ,
126
102
}
127
103
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 < ' _ > {
129
110
fn hash < H : Hasher > ( & self , state : & mut H ) {
130
111
self . body_id . hash ( state) ;
131
112
self . span . hash ( state) ;
132
- std:: mem:: discriminant ( & self . code ) . hash ( state) ;
133
113
}
134
114
}
135
115
116
+ const MISC_OBLIGATION_CAUSE_CODE : ObligationCauseCode < ' static > = MiscObligation ;
117
+
136
118
impl < ' tcx > ObligationCause < ' tcx > {
137
119
#[ inline]
138
120
pub fn new (
139
121
span : Span ,
140
122
body_id : hir:: HirId ,
141
123
code : ObligationCauseCode < ' tcx > ,
142
124
) -> 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
+ }
144
130
}
145
131
146
132
pub fn misc ( span : Span , body_id : hir:: HirId ) -> ObligationCause < ' tcx > {
147
133
ObligationCause :: new ( span, body_id, MiscObligation )
148
134
}
149
135
150
- pub fn dummy_with_span ( span : Span ) -> ObligationCause < ' tcx > {
151
- ObligationCause :: new ( span, hir:: CRATE_HIR_ID , MiscObligation )
152
- }
153
-
154
136
#[ inline( always) ]
155
137
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 }
157
143
}
158
144
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 ) ) )
161
147
}
162
148
163
149
pub fn span ( & self , tcx : TyCtxt < ' tcx > ) -> Span {
164
- match self . code {
150
+ match * self . code ( ) {
165
151
ObligationCauseCode :: CompareImplMethodObligation { .. }
166
152
| ObligationCauseCode :: MainFunctionType
167
153
| ObligationCauseCode :: StartFunctionType => {
@@ -174,6 +160,18 @@ impl<'tcx> ObligationCause<'tcx> {
174
160
_ => self . span ,
175
161
}
176
162
}
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
+ }
177
175
}
178
176
179
177
#[ derive( Clone , Debug , PartialEq , Eq , Hash , Lift ) ]
0 commit comments