Skip to content

Commit 0b71ffc

Browse files
committed
Auto merge of #100654 - compiler-errors:rework-point-at-arg, r=estebank
Rework "point at arg" suggestions to be more accurate Fixes #100560 Introduce a new set of `ObligationCauseCode`s which have additional bookeeping for what expression caused the obligation, and which predicate caused the obligation. This allows us to look at the _unsubstituted_ signature to find out which parameter or generic type argument caused an obligaton to fail. This means that (in most cases) we significantly improve the likelihood of pointing out the right argument that causes a fulfillment error. Also, since this logic isn't happening in just the `select_where_possible_and_mutate_fulfillment()` calls in the argument checking code, but instead during all trait selection in `FnCtxt`, we are also able to point out the correct argument even if inference means that we don't know whether an obligation has failed until well after a call expression has been checked. r? `@ghost`
2 parents c0941df + d577eb0 commit 0b71ffc

File tree

161 files changed

+1369
-780
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+1369
-780
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -740,12 +740,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
740740
err.help("...or use `match` instead of `let...else`");
741741
}
742742
_ => {
743-
if let ObligationCauseCode::BindingObligation(_, binding_span) =
744-
cause.code().peel_derives()
743+
if let ObligationCauseCode::BindingObligation(_, span)
744+
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
745+
= cause.code().peel_derives()
746+
&& let TypeError::RegionsPlaceholderMismatch = terr
745747
{
746-
if matches!(terr, TypeError::RegionsPlaceholderMismatch) {
747-
err.span_note(*binding_span, "the lifetime requirement is introduced here");
748-
}
748+
err.span_note(*span, "the lifetime requirement is introduced here");
749749
}
750750
}
751751
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
3535
let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
3636
return None;
3737
};
38-
let ObligationCauseCode::BindingObligation(_def_id, binding_span) = *parent.code() else {
38+
let (ObligationCauseCode::BindingObligation(_, binding_span) | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..))
39+
= *parent.code() else {
3940
return None;
4041
};
4142
let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
211211
);
212212
let mut err = self.tcx().sess.struct_span_err(span, &msg);
213213

214-
let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() {
214+
let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
215+
| ObligationCauseCode::ExprItemObligation(def_id, ..) =
216+
*cause.code()
217+
{
215218
err.span_label(span, "doesn't satisfy where-clause");
216219
err.span_label(
217220
self.tcx().def_span(def_id),

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
232232
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
233233
_ => cause.code(),
234234
}
235-
&& let (&ObligationCauseCode::ItemObligation(item_def_id), None) = (code, override_error_code)
235+
&& let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code)
236236
{
237237
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
238238
// lifetime as above, but called using a fully-qualified path to the method:

compiler/rustc_infer/src/infer/error_reporting/note.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
390390
if matches!(
391391
&trace.cause.code().peel_derives(),
392392
ObligationCauseCode::BindingObligation(..)
393+
| ObligationCauseCode::ExprBindingObligation(..)
393394
) =>
394395
{
395396
// Hack to get around the borrow checker because trace.cause has an `Rc`.
396-
if let ObligationCauseCode::BindingObligation(_, span) =
397+
if let ObligationCauseCode::BindingObligation(_, span)
398+
| ObligationCauseCode::ExprBindingObligation(_, span, ..) =
397399
&trace.cause.code().peel_derives()
398400
{
399401
let span = *span;

compiler/rustc_infer/src/infer/outlives/obligations.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
9797
cause.span,
9898
sup_type,
9999
match cause.code().peel_derives() {
100-
ObligationCauseCode::BindingObligation(_, span) => Some(*span),
100+
ObligationCauseCode::BindingObligation(_, span)
101+
| ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span),
101102
_ => None,
102103
},
103104
)

compiler/rustc_middle/src/traits/mod.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,23 @@ pub enum ObligationCauseCode<'tcx> {
234234
/// This is the trait reference from the given projection.
235235
ProjectionWf(ty::ProjectionTy<'tcx>),
236236

237-
/// In an impl of trait `X` for type `Y`, type `Y` must
238-
/// also implement all supertraits of `X`.
237+
/// Must satisfy all of the where-clause predicates of the
238+
/// given item.
239239
ItemObligation(DefId),
240240

241-
/// Like `ItemObligation`, but with extra detail on the source of the obligation.
241+
/// Like `ItemObligation`, but carries the span of the
242+
/// predicate when it can be identified.
242243
BindingObligation(DefId, Span),
243244

245+
/// Like `ItemObligation`, but carries the `HirId` of the
246+
/// expression that caused the obligation, and the `usize`
247+
/// indicates exactly which predicate it is in the list of
248+
/// instantiated predicates.
249+
ExprItemObligation(DefId, rustc_hir::HirId, usize),
250+
251+
/// Combines `ExprItemObligation` and `BindingObligation`.
252+
ExprBindingObligation(DefId, Span, rustc_hir::HirId, usize),
253+
244254
/// A type like `&'a T` is WF only if `T: 'a`.
245255
ReferenceOutlivesReferent(Ty<'tcx>),
246256

compiler/rustc_middle/src/ty/generics.rs

+15
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,21 @@ pub struct Generics {
122122
}
123123

124124
impl<'tcx> Generics {
125+
/// Looks through the generics and all parents to find the index of the
126+
/// given param def-id. This is in comparison to the `param_def_id_to_index`
127+
/// struct member, which only stores information about this item's own
128+
/// generics.
129+
pub fn param_def_id_to_index(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<u32> {
130+
if let Some(idx) = self.param_def_id_to_index.get(&def_id) {
131+
Some(*idx)
132+
} else if let Some(parent) = self.parent {
133+
let parent = tcx.generics_of(parent);
134+
parent.param_def_id_to_index(tcx, def_id)
135+
} else {
136+
None
137+
}
138+
}
139+
125140
#[inline]
126141
pub fn count(&self) -> usize {
127142
self.parent_count + self.params.len()

compiler/rustc_span/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,16 @@ impl Span {
664664
Some(self)
665665
}
666666

667+
/// Like `find_ancestor_inside`, but specifically for when spans might not
668+
/// overlaps. Take care when using this, and prefer `find_ancestor_inside`
669+
/// when you know that the spans are nested (modulo macro expansion).
670+
pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> {
671+
while !Span::eq_ctxt(self, other) {
672+
self = self.parent_callsite()?;
673+
}
674+
Some(self)
675+
}
676+
667677
/// Edition of the crate from which this span came.
668678
pub fn edition(self) -> edition::Edition {
669679
self.ctxt().edition()

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

+11-17
Original file line numberDiff line numberDiff line change
@@ -860,8 +860,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
860860
}
861861
}
862862

863-
err.emit();
864-
return;
863+
err
865864
}
866865

867866
ty::PredicateKind::WellFormed(ty) => {
@@ -1564,6 +1563,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
15641563
obligation.cause.code().peel_derives(),
15651564
ObligationCauseCode::ItemObligation(_)
15661565
| ObligationCauseCode::BindingObligation(_, _)
1566+
| ObligationCauseCode::ExprItemObligation(..)
1567+
| ObligationCauseCode::ExprBindingObligation(..)
15671568
| ObligationCauseCode::ObjectCastObligation(..)
15681569
| ObligationCauseCode::OpaqueType
15691570
);
@@ -2091,13 +2092,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
20912092
}
20922093
}
20932094

2094-
if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() {
2095+
if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() {
20952096
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
2096-
} else if let (
2097-
Ok(ref snippet),
2098-
&ObligationCauseCode::BindingObligation(def_id, _),
2099-
) =
2100-
(self.tcx.sess.source_map().span_to_snippet(span), obligation.cause.code())
2097+
} else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span)
2098+
&& let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..)
2099+
= *obligation.cause.code()
21012100
{
21022101
let generics = self.tcx.generics_of(def_id);
21032102
if generics.params.iter().any(|p| p.name != kw::SelfUpper)
@@ -2520,15 +2519,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
25202519
err: &mut Diagnostic,
25212520
obligation: &PredicateObligation<'tcx>,
25222521
) {
2523-
let (
2524-
ty::PredicateKind::Trait(pred),
2525-
&ObligationCauseCode::BindingObligation(item_def_id, span),
2526-
) = (
2527-
obligation.predicate.kind().skip_binder(),
2528-
obligation.cause.code().peel_derives(),
2529-
) else {
2530-
return;
2531-
};
2522+
let ty::PredicateKind::Trait(pred) = obligation.predicate.kind().skip_binder() else { return; };
2523+
let (ObligationCauseCode::BindingObligation(item_def_id, span)
2524+
| ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..))
2525+
= *obligation.cause.code().peel_derives() else { return; };
25322526
debug!(?pred, ?item_def_id, ?span);
25332527

25342528
let (Some(node), true) = (

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
143143
}
144144

145145
if let ObligationCauseCode::ItemObligation(item)
146-
| ObligationCauseCode::BindingObligation(item, _) = *obligation.cause.code()
146+
| ObligationCauseCode::BindingObligation(item, _)
147+
| ObligationCauseCode::ExprItemObligation(item, ..)
148+
| ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code()
147149
{
148150
// FIXME: maybe also have some way of handling methods
149151
// from other traits? That would require name resolution,

0 commit comments

Comments
 (0)