@@ -97,9 +97,7 @@ pub struct ObligationCause<'tcx> {
97
97
/// information.
98
98
pub body_id : hir:: HirId ,
99
99
100
- /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
101
- /// the time). `Some` otherwise.
102
- code : Option < Lrc < ObligationCauseCode < ' tcx > > > ,
100
+ code : InternedObligationCauseCode < ' tcx > ,
103
101
}
104
102
105
103
// This custom hash function speeds up hashing for `Obligation` deduplication
@@ -123,11 +121,7 @@ impl<'tcx> ObligationCause<'tcx> {
123
121
body_id : hir:: HirId ,
124
122
code : ObligationCauseCode < ' tcx > ,
125
123
) -> ObligationCause < ' tcx > {
126
- ObligationCause {
127
- span,
128
- body_id,
129
- code : if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some ( Lrc :: new ( code) ) } ,
130
- }
124
+ ObligationCause { span, body_id, code : code. into ( ) }
131
125
}
132
126
133
127
pub fn misc ( span : Span , body_id : hir:: HirId ) -> ObligationCause < ' tcx > {
@@ -136,15 +130,12 @@ impl<'tcx> ObligationCause<'tcx> {
136
130
137
131
#[ inline( always) ]
138
132
pub fn dummy ( ) -> ObligationCause < ' tcx > {
139
- ObligationCause { span : DUMMY_SP , body_id : hir :: CRATE_HIR_ID , code : None }
133
+ ObligationCause :: dummy_with_span ( DUMMY_SP )
140
134
}
141
135
136
+ #[ inline( always) ]
142
137
pub fn dummy_with_span ( span : Span ) -> ObligationCause < ' tcx > {
143
- ObligationCause { span, body_id : hir:: CRATE_HIR_ID , code : None }
144
- }
145
-
146
- pub fn make_mut_code ( & mut self ) -> & mut ObligationCauseCode < ' tcx > {
147
- Lrc :: make_mut ( self . code . get_or_insert_with ( || Lrc :: new ( MISC_OBLIGATION_CAUSE_CODE ) ) )
138
+ ObligationCause { span, body_id : hir:: CRATE_HIR_ID , code : Default :: default ( ) }
148
139
}
149
140
150
141
pub fn span ( & self , tcx : TyCtxt < ' tcx > ) -> Span {
@@ -164,14 +155,37 @@ impl<'tcx> ObligationCause<'tcx> {
164
155
165
156
#[ inline]
166
157
pub fn code ( & self ) -> & ObligationCauseCode < ' tcx > {
167
- self . code . as_deref ( ) . unwrap_or ( & MISC_OBLIGATION_CAUSE_CODE )
158
+ & self . code
168
159
}
169
160
170
- pub fn clone_code ( & self ) -> Lrc < ObligationCauseCode < ' tcx > > {
171
- match & self . code {
172
- Some ( code) => code. clone ( ) ,
173
- None => Lrc :: new ( MISC_OBLIGATION_CAUSE_CODE ) ,
174
- }
161
+ pub fn map_code (
162
+ & mut self ,
163
+ f : impl FnOnce ( InternedObligationCauseCode < ' tcx > ) -> ObligationCauseCode < ' tcx > ,
164
+ ) {
165
+ self . code = f ( std:: mem:: take ( & mut self . code ) ) . into ( ) ;
166
+ }
167
+
168
+ pub fn derived_cause (
169
+ mut self ,
170
+ parent_trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
171
+ variant : impl FnOnce ( DerivedObligationCause < ' tcx > ) -> ObligationCauseCode < ' tcx > ,
172
+ ) -> ObligationCause < ' tcx > {
173
+ /*!
174
+ * Creates a cause for obligations that are derived from
175
+ * `obligation` by a recursive search (e.g., for a builtin
176
+ * bound, or eventually a `auto trait Foo`). If `obligation`
177
+ * is itself a derived obligation, this is just a clone, but
178
+ * otherwise we create a "derived obligation" cause so as to
179
+ * keep track of the original root obligation for error
180
+ * reporting.
181
+ */
182
+
183
+ // NOTE(flaper87): As of now, it keeps track of the whole error
184
+ // chain. Ideally, we should have a way to configure this either
185
+ // by using -Z verbose or just a CLI argument.
186
+ self . code =
187
+ variant ( DerivedObligationCause { parent_trait_pred, parent_code : self . code } ) . into ( ) ;
188
+ self
175
189
}
176
190
}
177
191
@@ -182,6 +196,30 @@ pub struct UnifyReceiverContext<'tcx> {
182
196
pub substs : SubstsRef < ' tcx > ,
183
197
}
184
198
199
+ #[ derive( Clone , Debug , PartialEq , Eq , Hash , Lift , Default ) ]
200
+ pub struct InternedObligationCauseCode < ' tcx > {
201
+ /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
202
+ /// the time). `Some` otherwise.
203
+ code : Option < Lrc < ObligationCauseCode < ' tcx > > > ,
204
+ }
205
+
206
+ impl < ' tcx > ObligationCauseCode < ' tcx > {
207
+ #[ inline( always) ]
208
+ fn into ( self ) -> InternedObligationCauseCode < ' tcx > {
209
+ InternedObligationCauseCode {
210
+ code : if let MISC_OBLIGATION_CAUSE_CODE = self { None } else { Some ( Lrc :: new ( self ) ) } ,
211
+ }
212
+ }
213
+ }
214
+
215
+ impl < ' tcx > std:: ops:: Deref for InternedObligationCauseCode < ' tcx > {
216
+ type Target = ObligationCauseCode < ' tcx > ;
217
+
218
+ fn deref ( & self ) -> & Self :: Target {
219
+ self . code . as_deref ( ) . unwrap_or ( & MISC_OBLIGATION_CAUSE_CODE )
220
+ }
221
+ }
222
+
185
223
#[ derive( Clone , Debug , PartialEq , Eq , Hash , Lift ) ]
186
224
pub enum ObligationCauseCode < ' tcx > {
187
225
/// Not well classified or should be obvious from the span.
@@ -269,7 +307,7 @@ pub enum ObligationCauseCode<'tcx> {
269
307
/// The node of the function call.
270
308
call_hir_id : hir:: HirId ,
271
309
/// The obligation introduced by this argument.
272
- parent_code : Lrc < ObligationCauseCode < ' tcx > > ,
310
+ parent_code : InternedObligationCauseCode < ' tcx > ,
273
311
} ,
274
312
275
313
/// Error derived when matching traits/impls; see ObligationCause for more details
@@ -404,25 +442,27 @@ pub struct ImplDerivedObligationCause<'tcx> {
404
442
pub span : Span ,
405
443
}
406
444
407
- impl ObligationCauseCode < ' _ > {
445
+ impl < ' tcx > ObligationCauseCode < ' tcx > {
408
446
// Return the base obligation, ignoring derived obligations.
409
447
pub fn peel_derives ( & self ) -> & Self {
410
448
let mut base_cause = self ;
411
- loop {
412
- match base_cause {
413
- BuiltinDerivedObligation ( DerivedObligationCause { parent_code, .. } )
414
- | DerivedObligation ( DerivedObligationCause { parent_code, .. } )
415
- | FunctionArgumentObligation { parent_code, .. } => {
416
- base_cause = & parent_code;
417
- }
418
- ImplDerivedObligation ( obligation_cause) => {
419
- base_cause = & * obligation_cause. derived . parent_code ;
420
- }
421
- _ => break ,
422
- }
449
+ while let Some ( ( parent_code, _) ) = base_cause. parent ( ) {
450
+ base_cause = parent_code;
423
451
}
424
452
base_cause
425
453
}
454
+
455
+ pub fn parent ( & self ) -> Option < ( & Self , Option < ty:: PolyTraitPredicate < ' tcx > > ) > {
456
+ match self {
457
+ FunctionArgumentObligation { parent_code, .. } => Some ( ( parent_code, None ) ) ,
458
+ BuiltinDerivedObligation ( derived)
459
+ | DerivedObligation ( derived)
460
+ | ImplDerivedObligation ( box ImplDerivedObligationCause { derived, .. } ) => {
461
+ Some ( ( & derived. parent_code , Some ( derived. parent_trait_pred ) ) )
462
+ }
463
+ _ => None ,
464
+ }
465
+ }
426
466
}
427
467
428
468
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -472,7 +512,7 @@ pub struct DerivedObligationCause<'tcx> {
472
512
pub parent_trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
473
513
474
514
/// The parent trait had this cause.
475
- pub parent_code : Lrc < ObligationCauseCode < ' tcx > > ,
515
+ pub parent_code : InternedObligationCauseCode < ' tcx > ,
476
516
}
477
517
478
518
#[ derive( Clone , Debug , TypeFoldable , Lift ) ]
0 commit comments