Auto merge of #91844 - nnethercote:rm-ObligationCauseData-2, r=Mark-Simulacrum

Eliminate `ObligationCauseData`

This makes `Obligation` two words bigger, but avoids allocating a lot of the time.

I previously tried this in #73983 and it didn't help much, but local timings look more promising now.

r? `@ghost`
This commit is contained in:
bors 2021-12-20 00:40:58 +00:00
commit ed7a206843
22 changed files with 135 additions and 139 deletions

View File

@ -604,7 +604,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
terr: &TypeError<'tcx>, terr: &TypeError<'tcx>,
) { ) {
match cause.code { match *cause.code() {
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
let ty = self.resolve_vars_if_possible(root_ty); let ty = self.resolve_vars_if_possible(root_ty);
if ty.is_suggestable() { if ty.is_suggestable() {
@ -781,7 +781,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
_ => { _ => {
if let ObligationCauseCode::BindingObligation(_, binding_span) = if let ObligationCauseCode::BindingObligation(_, binding_span) =
cause.code.peel_derives() cause.code().peel_derives()
{ {
if matches!(terr, TypeError::RegionsPlaceholderMismatch) { if matches!(terr, TypeError::RegionsPlaceholderMismatch) {
err.span_note(*binding_span, "the lifetime requirement is introduced here"); err.span_note(*binding_span, "the lifetime requirement is introduced here");
@ -1729,10 +1729,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
_ => exp_found, _ => exp_found,
}; };
debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code); debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code());
if let Some(exp_found) = exp_found { if let Some(exp_found) = exp_found {
let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } = let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
&cause.code cause.code()
{ {
// Skip if the root_ty of the pattern is not the same as the expected_ty. // Skip if the root_ty of the pattern is not the same as the expected_ty.
// If these types aren't equal then we've probably peeled off a layer of arrays. // If these types aren't equal then we've probably peeled off a layer of arrays.
@ -1827,7 +1827,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_span, exp_found.expected, exp_found.found, exp_span, exp_found.expected, exp_found.found,
); );
if let ObligationCauseCode::CompareImplMethodObligation { .. } = &cause.code { if let ObligationCauseCode::CompareImplMethodObligation { .. } = cause.code() {
return; return;
} }
@ -1835,7 +1835,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.get_impl_future_output_ty(exp_found.expected), self.get_impl_future_output_ty(exp_found.expected),
self.get_impl_future_output_ty(exp_found.found), self.get_impl_future_output_ty(exp_found.found),
) { ) {
(Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code { (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() {
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
diag.multipart_suggestion( diag.multipart_suggestion(
"consider `await`ing on both `Future`s", "consider `await`ing on both `Future`s",
@ -1875,7 +1875,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
(Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code { (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code() {
ObligationCauseCode::Pattern { span: Some(span), .. } ObligationCauseCode::Pattern { span: Some(span), .. }
| ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(
@ -1927,7 +1927,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.map(|field| (field.ident.name, field.ty(self.tcx, expected_substs))) .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
.find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found)) .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
{ {
if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code { if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let suggestion = if expected_def.is_struct() { let suggestion = if expected_def.is_struct() {
format!("{}.{}", snippet, name) format!("{}.{}", snippet, name)
@ -2064,7 +2064,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
} }
if let MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = if let MatchExpressionArm(box MatchExpressionArmCause { source, .. }) =
trace.cause.code *trace.cause.code()
{ {
if let hir::MatchSource::TryDesugar = source { if let hir::MatchSource::TryDesugar = source {
if let Some((expected_ty, found_ty)) = self.values_str(trace.values) { if let Some((expected_ty, found_ty)) = self.values_str(trace.values) {
@ -2659,7 +2659,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
use self::FailureCode::*; use self::FailureCode::*;
use crate::traits::ObligationCauseCode::*; use crate::traits::ObligationCauseCode::*;
match self.code { match self.code() {
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
@ -2694,7 +2694,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
fn as_requirement_str(&self) -> &'static str { fn as_requirement_str(&self) -> &'static str {
use crate::traits::ObligationCauseCode::*; use crate::traits::ObligationCauseCode::*;
match self.code { match self.code() {
CompareImplMethodObligation { .. } => "method type is compatible with trait", CompareImplMethodObligation { .. } => "method type is compatible with trait",
CompareImplTypeObligation { .. } => "associated type is compatible with trait", CompareImplTypeObligation { .. } => "associated type is compatible with trait",
ExprAssignable => "expression is assignable", ExprAssignable => "expression is assignable",

View File

@ -31,15 +31,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}; };
// If we added a "points at argument expression" obligation, we remove it here, we care // If we added a "points at argument expression" obligation, we remove it here, we care
// about the original obligation only. // about the original obligation only.
let code = match &cause.code { let code = match cause.code() {
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code, ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
_ => &cause.code, _ => cause.code(),
}; };
let (parent, impl_def_id) = match code { let (parent, impl_def_id) = match code {
ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id), ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id),
_ => return None, _ => return None,
}; };
let binding_span = match parent.code { let binding_span = match *parent.code() {
ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span, ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span,
_ => return None, _ => return None,
}; };

View File

@ -208,7 +208,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
); );
let mut err = self.tcx().sess.struct_span_err(span, &msg); let mut err = self.tcx().sess.struct_span_err(span, &msg);
let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code { let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() {
err.span_label(span, "doesn't satisfy where-clause"); err.span_label(span, "doesn't satisfy where-clause");
err.span_label( err.span_label(
self.tcx().def_span(def_id), self.tcx().def_span(def_id),

View File

@ -42,7 +42,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
sup_r, sup_r,
) if **sub_r == RegionKind::ReStatic => { ) if **sub_r == RegionKind::ReStatic => {
// This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
// This may have a closure and it would cause ICE // This may have a closure and it would cause ICE
// through `find_param_with_region` (#78262). // through `find_param_with_region` (#78262).
let anon_reg_sup = tcx.is_suitable_region(sup_r)?; let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
@ -184,7 +184,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} }
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
if let ObligationCauseCode::ReturnValue(hir_id) if let ObligationCauseCode::ReturnValue(hir_id)
| ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
{ {
let parent_id = tcx.hir().get_parent_item(*hir_id); let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
@ -226,7 +226,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut override_error_code = None; let mut override_error_code = None;
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {
if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
// Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
// `'static` lifetime when called as a method on a binding: `bar.qux()`. // `'static` lifetime when called as a method on a binding: `bar.qux()`.
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
@ -235,9 +235,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} }
} }
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin { if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
let code = match &cause.code { let code = match cause.code() {
ObligationCauseCode::MatchImpl(parent, ..) => &parent.code, ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
_ => &cause.code, _ => cause.code(),
}; };
if let (ObligationCauseCode::ItemObligation(item_def_id), None) = if let (ObligationCauseCode::ItemObligation(item_def_id), None) =
(code, override_error_code) (code, override_error_code)

View File

@ -36,7 +36,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
ValuePairs::Types(sub_expected_found), ValuePairs::Types(sub_expected_found),
ValuePairs::Types(sup_expected_found), ValuePairs::Types(sup_expected_found),
CompareImplMethodObligation { trait_item_def_id, .. }, CompareImplMethodObligation { trait_item_def_id, .. },
) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) ) = (&sub_trace.values, &sup_trace.values, sub_trace.cause.code())
{ {
if sup_expected_found == sub_expected_found { if sup_expected_found == sub_expected_found {
self.emit_err( self.emit_err(

View File

@ -359,13 +359,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
match placeholder_origin { match placeholder_origin {
infer::Subtype(box ref trace) infer::Subtype(box ref trace)
if matches!( if matches!(
&trace.cause.code.peel_derives(), &trace.cause.code().peel_derives(),
ObligationCauseCode::BindingObligation(..) ObligationCauseCode::BindingObligation(..)
) => ) =>
{ {
// Hack to get around the borrow checker because trace.cause has an `Rc`. // Hack to get around the borrow checker because trace.cause has an `Rc`.
if let ObligationCauseCode::BindingObligation(_, span) = if let ObligationCauseCode::BindingObligation(_, span) =
&trace.cause.code.peel_derives() &trace.cause.code().peel_derives()
{ {
let span = *span; let span = *span;
let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);

View File

@ -1824,7 +1824,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
where where
F: FnOnce() -> Self, F: FnOnce() -> Self,
{ {
match cause.code { match *cause.code() {
traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => { traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => {
SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
} }

View File

@ -102,7 +102,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
infer::RelateParamBound( infer::RelateParamBound(
cause.span, cause.span,
sup_type, sup_type,
match cause.code.peel_derives() { match cause.code().peel_derives() {
ObligationCauseCode::BindingObligation(_, span) => Some(*span), ObligationCauseCode::BindingObligation(_, span) => Some(*span),
_ => None, _ => None,
}, },

View File

@ -81,7 +81,7 @@ impl TraitObligation<'_> {
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PredicateObligation<'_>, 32); static_assert_size!(PredicateObligation<'_>, 48);
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;

View File

@ -23,9 +23,7 @@ use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::Deref;
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
@ -80,38 +78,14 @@ pub enum Reveal {
/// The reason why we incurred this obligation; used for error reporting. /// The reason why we incurred this obligation; used for error reporting.
/// ///
/// As the happy path does not care about this struct, storing this on the heap /// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the
/// ends up increasing performance. /// best trade-off between keeping the type small (which makes copies cheaper)
/// while not doing too many heap allocations.
/// ///
/// We do not want to intern this as there are a lot of obligation causes which /// We do not want to intern this as there are a lot of obligation causes which
/// only live for a short period of time. /// only live for a short period of time.
#[derive(Clone, PartialEq, Eq, Hash, Lift)]
pub struct ObligationCause<'tcx> {
/// `None` for `ObligationCause::dummy`, `Some` otherwise.
data: Option<Lrc<ObligationCauseData<'tcx>>>,
}
const DUMMY_OBLIGATION_CAUSE_DATA: ObligationCauseData<'static> =
ObligationCauseData { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation };
// Correctly format `ObligationCause::dummy`.
impl<'tcx> fmt::Debug for ObligationCause<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ObligationCauseData::fmt(self, f)
}
}
impl<'tcx> Deref for ObligationCause<'tcx> {
type Target = ObligationCauseData<'tcx>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.data.as_deref().unwrap_or(&DUMMY_OBLIGATION_CAUSE_DATA)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Lift)] #[derive(Clone, Debug, PartialEq, Eq, Lift)]
pub struct ObligationCauseData<'tcx> { pub struct ObligationCause<'tcx> {
pub span: Span, pub span: Span,
/// The ID of the fn body that triggered this obligation. This is /// The ID of the fn body that triggered this obligation. This is
@ -122,17 +96,25 @@ pub struct ObligationCauseData<'tcx> {
/// information. /// information.
pub body_id: hir::HirId, pub body_id: hir::HirId,
pub code: ObligationCauseCode<'tcx>, /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
/// the time). `Some` otherwise.
code: Option<Lrc<ObligationCauseCode<'tcx>>>,
} }
impl Hash for ObligationCauseData<'_> { // This custom hash function speeds up hashing for `Obligation` deduplication
// greatly by skipping the `code` field, which can be large and complex. That
// shouldn't affect hash quality much since there are several other fields in
// `Obligation` which should be unique enough, especially the predicate itself
// which is hashed as an interned pointer. See #90996.
impl Hash for ObligationCause<'_> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.body_id.hash(state); self.body_id.hash(state);
self.span.hash(state); self.span.hash(state);
std::mem::discriminant(&self.code).hash(state);
} }
} }
const MISC_OBLIGATION_CAUSE_CODE: ObligationCauseCode<'static> = MiscObligation;
impl<'tcx> ObligationCause<'tcx> { impl<'tcx> ObligationCause<'tcx> {
#[inline] #[inline]
pub fn new( pub fn new(
@ -140,28 +122,32 @@ impl<'tcx> ObligationCause<'tcx> {
body_id: hir::HirId, body_id: hir::HirId,
code: ObligationCauseCode<'tcx>, code: ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> { ) -> ObligationCause<'tcx> {
ObligationCause { data: Some(Lrc::new(ObligationCauseData { span, body_id, code })) } ObligationCause {
span,
body_id,
code: if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some(Lrc::new(code)) },
}
} }
pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
ObligationCause::new(span, body_id, MiscObligation) ObligationCause::new(span, body_id, MiscObligation)
} }
pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
ObligationCause::new(span, hir::CRATE_HIR_ID, MiscObligation)
}
#[inline(always)] #[inline(always)]
pub fn dummy() -> ObligationCause<'tcx> { pub fn dummy() -> ObligationCause<'tcx> {
ObligationCause { data: None } ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: None }
} }
pub fn make_mut(&mut self) -> &mut ObligationCauseData<'tcx> { pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
Lrc::make_mut(self.data.get_or_insert_with(|| Lrc::new(DUMMY_OBLIGATION_CAUSE_DATA))) ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: None }
}
pub fn make_mut_code(&mut self) -> &mut ObligationCauseCode<'tcx> {
Lrc::make_mut(self.code.get_or_insert_with(|| Lrc::new(MISC_OBLIGATION_CAUSE_CODE)))
} }
pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
match self.code { match *self.code() {
ObligationCauseCode::CompareImplMethodObligation { .. } ObligationCauseCode::CompareImplMethodObligation { .. }
| ObligationCauseCode::MainFunctionType | ObligationCauseCode::MainFunctionType
| ObligationCauseCode::StartFunctionType => { | ObligationCauseCode::StartFunctionType => {
@ -174,6 +160,18 @@ impl<'tcx> ObligationCause<'tcx> {
_ => self.span, _ => self.span,
} }
} }
#[inline]
pub fn code(&self) -> &ObligationCauseCode<'tcx> {
self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE)
}
pub fn clone_code(&self) -> Lrc<ObligationCauseCode<'tcx>> {
match &self.code {
Some(code) => code.clone(),
None => Lrc::new(MISC_OBLIGATION_CAUSE_CODE),
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]

View File

@ -519,7 +519,7 @@ impl<T> Trait<T> for X {
proj_ty, proj_ty,
values, values,
body_owner_def_id, body_owner_def_id,
&cause.code, cause.code(),
); );
} }
(_, ty::Projection(proj_ty)) => { (_, ty::Projection(proj_ty)) => {

View File

@ -205,7 +205,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
self.note_obligation_cause_code( self.note_obligation_cause_code(
&mut err, &mut err,
&obligation.predicate, &obligation.predicate,
&obligation.cause.code, obligation.cause.code(),
&mut vec![], &mut vec![],
&mut Default::default(), &mut Default::default(),
); );
@ -255,7 +255,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// If this obligation was generated as a result of well-formedness checking, see if we // If this obligation was generated as a result of well-formedness checking, see if we
// can get a better error message by performing HIR-based well-formedness checking. // can get a better error message by performing HIR-based well-formedness checking.
if let ObligationCauseCode::WellFormed(Some(wf_loc)) = if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
root_obligation.cause.code.peel_derives() root_obligation.cause.code().peel_derives()
{ {
if let Some(cause) = self if let Some(cause) = self
.tcx .tcx
@ -272,7 +272,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::CompareImplTypeObligation { | ObligationCauseCode::CompareImplTypeObligation {
impl_item_def_id, impl_item_def_id,
trait_item_def_id, trait_item_def_id,
} = obligation.cause.code } = *obligation.cause.code()
{ {
self.report_extra_impl_obligation( self.report_extra_impl_obligation(
span, span,
@ -295,7 +295,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
let trait_ref = trait_predicate.to_poly_trait_ref(); let trait_ref = trait_predicate.to_poly_trait_ref();
let (post_message, pre_message, type_def) = self let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(&obligation.cause.code) .get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| { .map(|(t, s)| {
( (
format!(" in `{}`", t), format!(" in `{}`", t),
@ -376,8 +376,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
} }
let explanation = let explanation = if let ObligationCauseCode::MainFunctionType =
if obligation.cause.code == ObligationCauseCode::MainFunctionType { obligation.cause.code()
{
"consider using `()`, or a `Result`".to_owned() "consider using `()`, or a `Result`".to_owned()
} else { } else {
format!( format!(
@ -1305,7 +1306,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
); );
let is_normalized_ty_expected = !matches!( let is_normalized_ty_expected = !matches!(
obligation.cause.code.peel_derives(), obligation.cause.code().peel_derives(),
ObligationCauseCode::ItemObligation(_) ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ObjectCastObligation(_) | ObligationCauseCode::ObjectCastObligation(_)
@ -1620,9 +1621,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
let predicate = self.resolve_vars_if_possible(obligation.predicate); let predicate = self.resolve_vars_if_possible(obligation.predicate);
let span = obligation.cause.span; let span = obligation.cause.span;
debug!( debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code()));
?predicate, ?obligation.cause.code,
);
// Ambiguity errors are often caused as fallout from earlier errors. // Ambiguity errors are often caused as fallout from earlier errors.
// We ignore them if this `infcx` is tainted in some cases below. // We ignore them if this `infcx` is tainted in some cases below.
@ -1717,13 +1716,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
} }
} }
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
} else if let ( } else if let (
Ok(ref snippet), Ok(ref snippet),
ObligationCauseCode::BindingObligation(ref def_id, _), ObligationCauseCode::BindingObligation(ref def_id, _),
) = ) =
(self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code) (self.tcx.sess.source_map().span_to_snippet(span), obligation.cause.code())
{ {
let generics = self.tcx.generics_of(*def_id); let generics = self.tcx.generics_of(*def_id);
if generics.params.iter().any(|p| p.name != kw::SelfUpper) if generics.params.iter().any(|p| p.name != kw::SelfUpper)
@ -2006,7 +2005,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
self.note_obligation_cause_code( self.note_obligation_cause_code(
err, err,
&obligation.predicate, &obligation.predicate,
&obligation.cause.code, obligation.cause.code(),
&mut vec![], &mut vec![],
&mut Default::default(), &mut Default::default(),
); );
@ -2019,9 +2018,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
err: &mut DiagnosticBuilder<'tcx>, err: &mut DiagnosticBuilder<'tcx>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
) { ) {
let (pred, item_def_id, span) = let (pred, item_def_id, span) = match (
match (obligation.predicate.kind().skip_binder(), obligation.cause.code.peel_derives()) obligation.predicate.kind().skip_binder(),
{ obligation.cause.code().peel_derives(),
) {
( (
ty::PredicateKind::Trait(pred), ty::PredicateKind::Trait(pred),
&ObligationCauseCode::BindingObligation(item_def_id, span), &ObligationCauseCode::BindingObligation(item_def_id, span),

View File

@ -129,7 +129,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
)]; )];
match obligation.cause.code { match obligation.cause.code() {
ObligationCauseCode::BuiltinDerivedObligation(..) ObligationCauseCode::BuiltinDerivedObligation(..)
| ObligationCauseCode::ImplDerivedObligation(..) | ObligationCauseCode::ImplDerivedObligation(..)
| ObligationCauseCode::DerivedObligation(..) => {} | ObligationCauseCode::DerivedObligation(..) => {}
@ -141,7 +141,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
if let ObligationCauseCode::ItemObligation(item) if let ObligationCauseCode::ItemObligation(item)
| ObligationCauseCode::BindingObligation(item, _) = obligation.cause.code | ObligationCauseCode::BindingObligation(item, _) = *obligation.cause.code()
{ {
// FIXME: maybe also have some way of handling methods // FIXME: maybe also have some way of handling methods
// from other traits? That would require name resolution, // from other traits? That would require name resolution,

View File

@ -9,7 +9,6 @@ use crate::traits::normalize_projection_type;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{ use rustc_errors::{
error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
}; };
@ -497,7 +496,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
) { ) {
// It only make sense when suggesting dereferences for arguments // It only make sense when suggesting dereferences for arguments
let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
&obligation.cause.code obligation.cause.code()
{ {
parent_code.clone() parent_code.clone()
} else { } else {
@ -662,7 +661,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
_ => return, _ => return,
}; };
if matches!(obligation.cause.code, ObligationCauseCode::FunctionArgumentObligation { .. }) { if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
{
// When the obligation error has been ensured to have been caused by // When the obligation error has been ensured to have been caused by
// an argument, the `obligation.cause.span` points at the expression // an argument, the `obligation.cause.span` points at the expression
// of the argument, so we can provide a suggestion. Otherwise, we give // of the argument, so we can provide a suggestion. Otherwise, we give
@ -688,13 +688,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let span = obligation.cause.span; let span = obligation.cause.span;
let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
&obligation.cause.code obligation.cause.code()
{ {
parent_code.clone() &parent_code
} else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
span.ctxt().outer_expn_data().kind span.ctxt().outer_expn_data().kind
{ {
Lrc::new(obligation.cause.code.clone()) obligation.cause.code()
} else { } else {
return false; return false;
}; };
@ -805,10 +805,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return false; return false;
}; };
if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { if let ObligationCauseCode::ImplDerivedObligation(obligation) = code {
try_borrowing(obligation.parent_trait_ref, &[]) try_borrowing(obligation.parent_trait_ref, &[])
} else if let ObligationCauseCode::BindingObligation(_, _) } else if let ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ItemObligation(_) = &*code | ObligationCauseCode::ItemObligation(_) = code
{ {
try_borrowing(*poly_trait_ref, &never_suggest_borrow) try_borrowing(*poly_trait_ref, &never_suggest_borrow)
} else { } else {
@ -886,7 +886,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
) { ) {
let span = obligation.cause.span; let span = obligation.cause.span;
if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code.peel_derives() { if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() {
let hir = self.tcx.hir(); let hir = self.tcx.hir();
if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) { if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
if let hir::Node::Expr(expr) = node { if let hir::Node::Expr(expr) = node {
@ -945,7 +945,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
) { ) {
let points_at_arg = matches!( let points_at_arg = matches!(
obligation.cause.code, obligation.cause.code(),
ObligationCauseCode::FunctionArgumentObligation { .. }, ObligationCauseCode::FunctionArgumentObligation { .. },
); );
@ -1072,7 +1072,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
) -> bool { ) -> bool {
match obligation.cause.code.peel_derives() { match obligation.cause.code().peel_derives() {
// Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
ObligationCauseCode::SizedReturnType => {} ObligationCauseCode::SizedReturnType => {}
_ => return false, _ => return false,
@ -1267,7 +1267,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err: &mut DiagnosticBuilder<'_>, err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
) { ) {
match obligation.cause.code.peel_derives() { match obligation.cause.code().peel_derives() {
ObligationCauseCode::SizedReturnType => {} ObligationCauseCode::SizedReturnType => {}
_ => return, _ => return,
} }
@ -1461,7 +1461,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}; };
let mut generator = None; let mut generator = None;
let mut outer_generator = None; let mut outer_generator = None;
let mut next_code = Some(&obligation.cause.code); let mut next_code = Some(obligation.cause.code());
let mut seen_upvar_tys_infer_tuple = false; let mut seen_upvar_tys_infer_tuple = false;

View File

@ -96,7 +96,7 @@ pub struct PendingPredicateObligation<'tcx> {
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PendingPredicateObligation<'_>, 56); static_assert_size!(PendingPredicateObligation<'_>, 72);
impl<'a, 'tcx> FulfillmentContext<'tcx> { impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context. /// Creates a new fulfillment context.

View File

@ -29,7 +29,6 @@ use crate::traits::project::ProjectionCacheKeyExt;
use crate::traits::ProjectionCacheKey; use crate::traits::ProjectionCacheKey;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -2384,7 +2383,7 @@ impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> {
// by using -Z verbose or just a CLI argument. // by using -Z verbose or just a CLI argument.
let derived_cause = DerivedObligationCause { let derived_cause = DerivedObligationCause {
parent_trait_ref: obligation.predicate.to_poly_trait_ref(), parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
parent_code: Lrc::new(obligation.cause.code.clone()), parent_code: obligation.cause.clone_code(),
}; };
let derived_code = variant(derived_cause); let derived_code = variant(derived_cause);
ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)

View File

@ -232,7 +232,7 @@ pub fn predicates_for_generics<'tcx>(
debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);
iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| { iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| {
let cause = match cause.code { let cause = match *cause.code() {
traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new( traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new(
cause.span, cause.span,
cause.body_id, cause.body_id,

View File

@ -1,7 +1,6 @@
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::opaque_types::required_region_bounds; use crate::opaque_types::required_region_bounds;
use crate::traits; use crate::traits;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
@ -227,7 +226,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
if let Some(impl_item_span) = if let Some(impl_item_span) =
items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
{ {
cause.make_mut().span = impl_item_span; cause.span = impl_item_span;
} }
} }
} }
@ -242,7 +241,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span) items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span)
}) })
{ {
cause.make_mut().span = impl_item_span; cause.span = impl_item_span;
} }
} }
} }
@ -302,9 +301,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let derived_cause = traits::DerivedObligationCause { let derived_cause = traits::DerivedObligationCause {
// FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref), parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
parent_code: Lrc::new(obligation.cause.code.clone()), parent_code: obligation.cause.clone_code(),
}; };
cause.make_mut().code = *cause.make_mut_code() =
traits::ObligationCauseCode::DerivedObligation(derived_cause); traits::ObligationCauseCode::DerivedObligation(derived_cause);
} }
extend_cause_with_original_assoc_item_obligation( extend_cause_with_original_assoc_item_obligation(
@ -343,7 +342,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) = if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) =
item.map(|i| &i.kind) item.map(|i| &i.kind)
{ {
new_cause.make_mut().span = self_ty.span; new_cause.span = self_ty.span;
} }
} }
traits::Obligation::with_depth( traits::Obligation::with_depth(

View File

@ -1444,7 +1444,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let mut err; let mut err;
let mut unsized_return = false; let mut unsized_return = false;
match cause.code { match *cause.code() {
ObligationCauseCode::ReturnNoExpression => { ObligationCauseCode::ReturnNoExpression => {
err = struct_span_err!( err = struct_span_err!(
fcx.tcx.sess, fcx.tcx.sess,

View File

@ -232,7 +232,7 @@ fn compare_predicate_entailment<'tcx>(
inh.register_predicates(obligations); inh.register_predicates(obligations);
let mut cause = cause.clone(); let mut cause = cause.clone();
cause.make_mut().span = span; cause.span = span;
inh.register_predicate(traits::Obligation::new(cause, param_env, predicate)); inh.register_predicate(traits::Obligation::new(cause, param_env, predicate));
} }
@ -293,7 +293,7 @@ fn compare_predicate_entailment<'tcx>(
let (impl_err_span, trait_err_span) = let (impl_err_span, trait_err_span) =
extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m); extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m);
cause.make_mut().span = impl_err_span; cause.span = impl_err_span;
let mut diag = struct_span_err!( let mut diag = struct_span_err!(
tcx.sess, tcx.sess,
@ -1043,7 +1043,7 @@ crate fn compare_const_impl<'tcx>(
// Locate the Span containing just the type of the offending impl // Locate the Span containing just the type of the offending impl
match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind { match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span, ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
_ => bug!("{:?} is not a impl const", impl_c), _ => bug!("{:?} is not a impl const", impl_c),
} }

View File

@ -997,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
result_code result_code
} }
let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(Lrc::new(error.obligation.cause.code.clone())) { let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(error.obligation.cause.clone_code()) {
ObligationCauseCode::BuiltinDerivedObligation(code) | ObligationCauseCode::BuiltinDerivedObligation(code) |
ObligationCauseCode::ImplDerivedObligation(code) | ObligationCauseCode::ImplDerivedObligation(code) |
ObligationCauseCode::DerivedObligation(code) => { ObligationCauseCode::DerivedObligation(code) => {
@ -1040,18 +1040,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
// We make sure that only *one* argument matches the obligation failure // We make sure that only *one* argument matches the obligation failure
// and we assign the obligation's span to its expression's. // and we assign the obligation's span to its expression's.
error.obligation.cause.make_mut().span = args[ref_in].span; error.obligation.cause.span = args[ref_in].span;
let code = error.obligation.cause.code.clone(); let parent_code = error.obligation.cause.clone_code();
error.obligation.cause.make_mut().code = *error.obligation.cause.make_mut_code() =
ObligationCauseCode::FunctionArgumentObligation { ObligationCauseCode::FunctionArgumentObligation {
arg_hir_id: args[ref_in].hir_id, arg_hir_id: args[ref_in].hir_id,
call_hir_id: expr.hir_id, call_hir_id: expr.hir_id,
parent_code: Lrc::new(code), parent_code,
}; };
} else if error.obligation.cause.make_mut().span == call_sp { } else if error.obligation.cause.span == call_sp {
// Make function calls point at the callee, not the whole thing. // Make function calls point at the callee, not the whole thing.
if let hir::ExprKind::Call(callee, _) = expr.kind { if let hir::ExprKind::Call(callee, _) = expr.kind {
error.obligation.cause.make_mut().span = callee.span; error.obligation.cause.span = callee.span;
} }
} }
} }
@ -1092,7 +1092,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty); let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
if ty == predicate.self_ty() { if ty == predicate.self_ty() {
error.obligation.cause.make_mut().span = hir_ty.span; error.obligation.cause.span = hir_ty.span;
} }
} }
} }

View File

@ -832,7 +832,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (data, p, parent_p) in unsatisfied_predicates for (data, p, parent_p) in unsatisfied_predicates
.iter() .iter()
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c))) .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
.filter_map(|(p, parent, c)| match c.code { .filter_map(|(p, parent, c)| match c.code() {
ObligationCauseCode::ImplDerivedObligation(ref data) => { ObligationCauseCode::ImplDerivedObligation(ref data) => {
Some((data, p, parent)) Some((data, p, parent))
} }