@@ -97,9 +97,7 @@ pub struct ObligationCause<'tcx> {
9797 /// information.
9898 pub body_id : hir:: HirId ,
9999
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 > ,
103101}
104102
105103// This custom hash function speeds up hashing for `Obligation` deduplication
@@ -123,11 +121,7 @@ impl<'tcx> ObligationCause<'tcx> {
123121 body_id : hir:: HirId ,
124122 code : ObligationCauseCode < ' tcx > ,
125123 ) -> 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 ( ) }
131125 }
132126
133127 pub fn misc ( span : Span , body_id : hir:: HirId ) -> ObligationCause < ' tcx > {
@@ -136,15 +130,12 @@ impl<'tcx> ObligationCause<'tcx> {
136130
137131 #[ inline( always) ]
138132 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 )
140134 }
141135
136+ #[ inline( always) ]
142137 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 ( ) }
148139 }
149140
150141 pub fn span ( & self , tcx : TyCtxt < ' tcx > ) -> Span {
@@ -164,14 +155,37 @@ impl<'tcx> ObligationCause<'tcx> {
164155
165156 #[ inline]
166157 pub fn code ( & self ) -> & ObligationCauseCode < ' tcx > {
167- self . code . as_deref ( ) . unwrap_or ( & MISC_OBLIGATION_CAUSE_CODE )
158+ & self . code
168159 }
169160
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
175189 }
176190}
177191
@@ -182,6 +196,30 @@ pub struct UnifyReceiverContext<'tcx> {
182196 pub substs : SubstsRef < ' tcx > ,
183197}
184198
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+
185223#[ derive( Clone , Debug , PartialEq , Eq , Hash , Lift ) ]
186224pub enum ObligationCauseCode < ' tcx > {
187225 /// Not well classified or should be obvious from the span.
@@ -269,7 +307,7 @@ pub enum ObligationCauseCode<'tcx> {
269307 /// The node of the function call.
270308 call_hir_id : hir:: HirId ,
271309 /// The obligation introduced by this argument.
272- parent_code : Lrc < ObligationCauseCode < ' tcx > > ,
310+ parent_code : InternedObligationCauseCode < ' tcx > ,
273311 } ,
274312
275313 /// Error derived when matching traits/impls; see ObligationCause for more details
@@ -404,25 +442,27 @@ pub struct ImplDerivedObligationCause<'tcx> {
404442 pub span : Span ,
405443}
406444
407- impl ObligationCauseCode < ' _ > {
445+ impl < ' tcx > ObligationCauseCode < ' tcx > {
408446 // Return the base obligation, ignoring derived obligations.
409447 pub fn peel_derives ( & self ) -> & Self {
410448 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;
423451 }
424452 base_cause
425453 }
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+ }
426466}
427467
428468// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -472,7 +512,7 @@ pub struct DerivedObligationCause<'tcx> {
472512 pub parent_trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
473513
474514 /// The parent trait had this cause.
475- pub parent_code : Lrc < ObligationCauseCode < ' tcx > > ,
515+ pub parent_code : InternedObligationCauseCode < ' tcx > ,
476516}
477517
478518#[ derive( Clone , Debug , TypeFoldable , Lift ) ]
0 commit comments