Skip to content

Commit 5fd3786

Browse files
committed
Properly track ImplObligations
Instead of probing for all possible impls that could have caused an `ImplObligation`, keep track of its `DefId` and obligation spans for accurate error reporting. Follow up to #89580. Addresses #89418. Remove some unnecessary clones. Tweak output for auto trait impl obligations.
1 parent 547369d commit 5fd3786

24 files changed

+421
-213
lines changed

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
3131
// about the original obligation only.
3232
let code = match cause.code() {
3333
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
34-
_ => cause.code(),
34+
code => code,
3535
};
3636
let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
3737
return None;

compiler/rustc_middle/src/traits/mod.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub enum ObligationCauseCode<'tcx> {
257257

258258
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
259259

260-
ImplDerivedObligation(DerivedObligationCause<'tcx>),
260+
ImplDerivedObligation(Box<ImplDerivedObligationCause<'tcx>>),
261261

262262
DerivedObligation(DerivedObligationCause<'tcx>),
263263

@@ -396,16 +396,29 @@ pub enum WellFormedLoc {
396396
},
397397
}
398398

399+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
400+
pub struct ImplDerivedObligationCause<'tcx> {
401+
pub derived: DerivedObligationCause<'tcx>,
402+
pub impl_def_id: DefId,
403+
pub span: Span,
404+
}
405+
399406
impl ObligationCauseCode<'_> {
400407
// Return the base obligation, ignoring derived obligations.
401408
pub fn peel_derives(&self) -> &Self {
402409
let mut base_cause = self;
403-
while let BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
404-
| ImplDerivedObligation(DerivedObligationCause { parent_code, .. })
405-
| DerivedObligation(DerivedObligationCause { parent_code, .. })
406-
| FunctionArgumentObligation { parent_code, .. } = base_cause
407-
{
408-
base_cause = &parent_code;
410+
loop {
411+
match base_cause {
412+
BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
413+
| DerivedObligation(DerivedObligationCause { parent_code, .. })
414+
| FunctionArgumentObligation { parent_code, .. } => {
415+
base_cause = &parent_code;
416+
}
417+
ImplDerivedObligation(obligation_cause) => {
418+
base_cause = &*obligation_cause.derived.parent_code;
419+
}
420+
_ => break,
421+
}
409422
}
410423
base_cause
411424
}

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+82-39
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
507507
let body_id = obligation.cause.body_id;
508508
let span = obligation.cause.span;
509509
let real_trait_pred = match &*code {
510-
ObligationCauseCode::ImplDerivedObligation(cause)
511-
| ObligationCauseCode::DerivedObligation(cause)
510+
ObligationCauseCode::ImplDerivedObligation(cause) => cause.derived.parent_trait_pred,
511+
ObligationCauseCode::DerivedObligation(cause)
512512
| ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred,
513513
_ => trait_pred,
514514
};
@@ -790,8 +790,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
790790
return false;
791791
};
792792

793-
if let ObligationCauseCode::ImplDerivedObligation(obligation) = code {
794-
try_borrowing(obligation.parent_trait_pred, &[])
793+
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
794+
try_borrowing(cause.derived.parent_trait_pred, &[])
795795
} else if let ObligationCauseCode::BindingObligation(_, _)
796796
| ObligationCauseCode::ItemObligation(_) = code
797797
{
@@ -1433,13 +1433,43 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14331433
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
14341434
next_code = Some(parent_code.as_ref());
14351435
}
1436+
ObligationCauseCode::ImplDerivedObligation(cause) => {
1437+
let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
1438+
debug!(
1439+
"maybe_note_obligation_cause_for_async_await: ImplDerived \
1440+
parent_trait_ref={:?} self_ty.kind={:?}",
1441+
cause.derived.parent_trait_pred,
1442+
ty.kind()
1443+
);
1444+
1445+
match *ty.kind() {
1446+
ty::Generator(did, ..) => {
1447+
generator = generator.or(Some(did));
1448+
outer_generator = Some(did);
1449+
}
1450+
ty::GeneratorWitness(..) => {}
1451+
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
1452+
// By introducing a tuple of upvar types into the chain of obligations
1453+
// of a generator, the first non-generator item is now the tuple itself,
1454+
// we shall ignore this.
1455+
1456+
seen_upvar_tys_infer_tuple = true;
1457+
}
1458+
_ if generator.is_none() => {
1459+
trait_ref = Some(cause.derived.parent_trait_pred.skip_binder());
1460+
target_ty = Some(ty);
1461+
}
1462+
_ => {}
1463+
}
1464+
1465+
next_code = Some(cause.derived.parent_code.as_ref());
1466+
}
14361467
ObligationCauseCode::DerivedObligation(derived_obligation)
1437-
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
1438-
| ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
1468+
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => {
14391469
let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
14401470
debug!(
14411471
"maybe_note_obligation_cause_for_async_await: \
1442-
parent_trait_ref={:?} self_ty.kind={:?}",
1472+
parent_trait_ref={:?} self_ty.kind={:?}",
14431473
derived_obligation.parent_trait_pred,
14441474
ty.kind()
14451475
);
@@ -2166,59 +2196,72 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
21662196
}
21672197
}
21682198
ObligationCauseCode::ImplDerivedObligation(ref data) => {
2169-
let mut parent_trait_pred = self.resolve_vars_if_possible(data.parent_trait_pred);
2199+
let mut parent_trait_pred =
2200+
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
21702201
parent_trait_pred.remap_constness_diag(param_env);
21712202
let parent_def_id = parent_trait_pred.def_id();
21722203
let msg = format!(
21732204
"required because of the requirements on the impl of `{}` for `{}`",
21742205
parent_trait_pred.print_modifiers_and_trait_path(),
21752206
parent_trait_pred.skip_binder().self_ty()
21762207
);
2177-
let mut candidates = vec![];
2178-
self.tcx.for_each_relevant_impl(
2179-
parent_def_id,
2180-
parent_trait_pred.self_ty().skip_binder(),
2181-
|impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) {
2182-
Some(Node::Item(hir::Item {
2183-
kind: hir::ItemKind::Impl(hir::Impl { .. }),
2184-
..
2185-
})) => {
2186-
candidates.push(impl_def_id);
2187-
}
2188-
_ => {}
2189-
},
2190-
);
2191-
match &candidates[..] {
2192-
[def_id] => match self.tcx.hir().get_if_local(*def_id) {
2193-
Some(Node::Item(hir::Item {
2194-
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
2195-
..
2196-
})) => {
2197-
let mut spans = Vec::with_capacity(2);
2198-
if let Some(trait_ref) = of_trait {
2199-
spans.push(trait_ref.path.span);
2200-
}
2201-
spans.push(self_ty.span);
2202-
err.span_note(spans, &msg)
2208+
let mut is_auto_trait = false;
2209+
match self.tcx.hir().get_if_local(data.impl_def_id) {
2210+
Some(Node::Item(hir::Item {
2211+
kind: hir::ItemKind::Trait(is_auto, ..),
2212+
ident,
2213+
..
2214+
})) => {
2215+
// FIXME: we should do something else so that it works even on crate foreign
2216+
// auto traits.
2217+
is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
2218+
err.span_note(ident.span, &msg)
2219+
}
2220+
Some(Node::Item(hir::Item {
2221+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
2222+
..
2223+
})) => {
2224+
let mut spans = Vec::with_capacity(2);
2225+
if let Some(trait_ref) = of_trait {
2226+
spans.push(trait_ref.path.span);
22032227
}
2204-
_ => err.note(&msg),
2205-
},
2228+
spans.push(self_ty.span);
2229+
err.span_note(spans, &msg)
2230+
}
22062231
_ => err.note(&msg),
22072232
};
22082233

22092234
let mut parent_predicate = parent_trait_pred.to_predicate(tcx);
2210-
let mut data = data;
2235+
let mut data = &data.derived;
22112236
let mut count = 0;
22122237
seen_requirements.insert(parent_def_id);
2238+
if is_auto_trait {
2239+
// We don't want to point at the ADT saying "required because it appears within
2240+
// the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`.
2241+
while let ObligationCauseCode::BuiltinDerivedObligation(derived) =
2242+
&*data.parent_code
2243+
{
2244+
let child_trait_ref =
2245+
self.resolve_vars_if_possible(derived.parent_trait_pred);
2246+
let child_def_id = child_trait_ref.def_id();
2247+
if seen_requirements.insert(child_def_id) {
2248+
break;
2249+
}
2250+
data = derived;
2251+
parent_predicate = child_trait_ref.to_predicate(tcx);
2252+
parent_trait_pred = child_trait_ref;
2253+
}
2254+
}
22132255
while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
22142256
// Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
2215-
let child_trait_pred = self.resolve_vars_if_possible(child.parent_trait_pred);
2257+
let child_trait_pred =
2258+
self.resolve_vars_if_possible(child.derived.parent_trait_pred);
22162259
let child_def_id = child_trait_pred.def_id();
22172260
if seen_requirements.insert(child_def_id) {
22182261
break;
22192262
}
22202263
count += 1;
2221-
data = child;
2264+
data = &child.derived;
22222265
parent_predicate = child_trait_pred.to_predicate(tcx);
22232266
parent_trait_pred = child_trait_pred;
22242267
}

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+44-31
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,17 @@ use rustc_span::def_id::DefId;
1818

1919
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
2020
use crate::traits::select::TraitObligationExt;
21-
use crate::traits::util;
22-
use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
23-
use crate::traits::ImplSource;
24-
use crate::traits::Normalized;
25-
use crate::traits::OutputTypeParameterMismatch;
26-
use crate::traits::Selection;
27-
use crate::traits::TraitNotObjectSafe;
28-
use crate::traits::VtblSegment;
29-
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
21+
use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
3022
use crate::traits::{
31-
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
32-
ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
33-
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
34-
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
23+
BuiltinDerivedObligation, DerivedObligationCause, ImplDerivedObligation,
24+
ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData,
25+
ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceDiscriminantKindData,
26+
ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData,
27+
ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized,
28+
ObjectCastObligation, Obligation, ObligationCause, OutputTypeParameterMismatch,
29+
PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, TraitObligation,
30+
Unimplemented, VtblSegment,
3531
};
36-
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
37-
use crate::traits::{Obligation, ObligationCause};
38-
use crate::traits::{SelectionError, Unimplemented};
3932

4033
use super::BuiltinImplConditions;
4134
use super::SelectionCandidate::{self, *};
@@ -321,28 +314,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
321314
debug!(?nested, "vtable_auto_impl");
322315
ensure_sufficient_stack(|| {
323316
let cause = obligation.derived_cause(BuiltinDerivedObligation);
324-
let mut obligations = self.collect_predicates_for_types(
325-
obligation.param_env,
326-
cause,
327-
obligation.recursion_depth + 1,
328-
trait_def_id,
329-
nested,
330-
);
331317

332318
let trait_obligations: Vec<PredicateObligation<'_>> =
333319
self.infcx.commit_unconditionally(|_| {
334320
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
335321
let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
336-
let cause = obligation.derived_cause(ImplDerivedObligation);
337322
self.impl_or_trait_obligations(
338-
cause,
323+
&cause,
339324
obligation.recursion_depth + 1,
340325
obligation.param_env,
341326
trait_def_id,
342327
&trait_ref.substs,
328+
obligation.predicate,
343329
)
344330
});
345331

332+
let mut obligations = self.collect_predicates_for_types(
333+
obligation.param_env,
334+
cause,
335+
obligation.recursion_depth + 1,
336+
trait_def_id,
337+
nested,
338+
);
339+
346340
// Adds the predicates from the trait. Note that this contains a `Self: Trait`
347341
// predicate as usual. It won't have any effect since auto traits are coinductive.
348342
obligations.extend(trait_obligations);
@@ -365,14 +359,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
365359
self.infcx.commit_unconditionally(|_| {
366360
let substs = self.rematch_impl(impl_def_id, obligation);
367361
debug!(?substs, "impl substs");
368-
let cause = obligation.derived_cause(ImplDerivedObligation);
369362
ensure_sufficient_stack(|| {
370363
self.vtable_impl(
371364
impl_def_id,
372365
substs,
373-
cause,
366+
&obligation.cause,
374367
obligation.recursion_depth + 1,
375368
obligation.param_env,
369+
obligation.predicate,
376370
)
377371
})
378372
})
@@ -382,9 +376,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
382376
&mut self,
383377
impl_def_id: DefId,
384378
substs: Normalized<'tcx, SubstsRef<'tcx>>,
385-
cause: ObligationCause<'tcx>,
379+
cause: &ObligationCause<'tcx>,
386380
recursion_depth: usize,
387381
param_env: ty::ParamEnv<'tcx>,
382+
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
388383
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
389384
debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl");
390385

@@ -394,6 +389,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
394389
param_env,
395390
impl_def_id,
396391
&substs.value,
392+
parent_trait_pred,
397393
);
398394

399395
debug!(?impl_obligations, "vtable_impl");
@@ -566,11 +562,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
566562
let substs = trait_ref.substs;
567563

568564
let trait_obligations = self.impl_or_trait_obligations(
569-
obligation.cause.clone(),
565+
&obligation.cause,
570566
obligation.recursion_depth,
571567
obligation.param_env,
572568
trait_def_id,
573569
&substs,
570+
obligation.predicate,
574571
);
575572

576573
debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
@@ -1073,14 +1070,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10731070
});
10741071
let substs = self.rematch_impl(impl_def_id, &new_obligation);
10751072
debug!(?substs, "impl substs");
1076-
let cause = obligation.derived_cause(ImplDerivedObligation);
1073+
1074+
let derived = DerivedObligationCause {
1075+
parent_trait_pred: obligation.predicate,
1076+
parent_code: obligation.cause.clone_code(),
1077+
};
1078+
let derived_code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
1079+
derived,
1080+
impl_def_id,
1081+
span: obligation.cause.span,
1082+
}));
1083+
1084+
let cause = ObligationCause::new(
1085+
obligation.cause.span,
1086+
obligation.cause.body_id,
1087+
derived_code,
1088+
);
10771089
ensure_sufficient_stack(|| {
10781090
self.vtable_impl(
10791091
impl_def_id,
10801092
substs,
1081-
cause,
1093+
&cause,
10821094
new_obligation.recursion_depth + 1,
10831095
new_obligation.param_env,
1096+
obligation.predicate,
10841097
)
10851098
})
10861099
});

0 commit comments

Comments
 (0)