1
Fork 0

Use only one label for multiple unsatisfied bounds on type (astconv)

This commit is contained in:
Esteban Küber 2024-01-26 20:07:37 +00:00
parent 0b7730105f
commit 3691ab8e7a
2 changed files with 29 additions and 15 deletions

View file

@ -461,22 +461,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return err.emit(); return err.emit();
} }
let mut bound_spans = Vec::new(); let mut bound_spans: FxHashMap<Span, Vec<String>> = Default::default();
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
let msg = format!( let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
"doesn't satisfy `{}`",
if obligation.len() > 50 { quiet } else { obligation }
);
match &self_ty.kind() { match &self_ty.kind() {
// Point at the type that couldn't satisfy the bound. // Point at the type that couldn't satisfy the bound.
ty::Adt(def, _) => bound_spans.push((tcx.def_span(def.did()), msg)), ty::Adt(def, _) => {
bound_spans.entry(tcx.def_span(def.did())).or_default().push(msg)
}
// Point at the trait object that couldn't satisfy the bound. // Point at the trait object that couldn't satisfy the bound.
ty::Dynamic(preds, _, _) => { ty::Dynamic(preds, _, _) => {
for pred in preds.iter() { for pred in preds.iter() {
match pred.skip_binder() { match pred.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => { ty::ExistentialPredicate::Trait(tr) => {
bound_spans.push((tcx.def_span(tr.def_id), msg.clone())) bound_spans
.entry(tcx.def_span(tr.def_id))
.or_default()
.push(msg.clone());
} }
ty::ExistentialPredicate::Projection(_) ty::ExistentialPredicate::Projection(_)
| ty::ExistentialPredicate::AutoTrait(_) => {} | ty::ExistentialPredicate::AutoTrait(_) => {}
@ -485,7 +487,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
// Point at the closure that couldn't satisfy the bound. // Point at the closure that couldn't satisfy the bound.
ty::Closure(def_id, _) => { ty::Closure(def_id, _) => {
bound_spans.push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))) bound_spans
.entry(tcx.def_span(*def_id))
.or_default()
.push(format!("`{quiet}`"));
} }
_ => {} _ => {}
} }
@ -554,12 +559,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
); );
bound_spans.sort(); let mut bound_spans: Vec<(Span, Vec<String>)> = bound_spans
bound_spans.dedup(); .into_iter()
for (span, msg) in bound_spans { .map(|(span, mut bounds)| {
bounds.sort();
bounds.dedup();
(span, bounds)
})
.collect();
bound_spans.sort_by_key(|(span, _)| *span);
for (span, bounds) in bound_spans {
if !tcx.sess.source_map().is_span_accessible(span) { if !tcx.sess.source_map().is_span_accessible(span) {
continue; continue;
} }
let msg = match &bounds[..] {
[bound] => format!("doesn't satisfy {bound}"),
[bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")),
[] => unreachable!(),
};
err.span_label(span, msg); err.span_label(span, msg);
} }
add_def_label(&mut err); add_def_label(&mut err);

View file

@ -4,10 +4,7 @@ error: the associated type `X` exists for `S<Featureless, Featureless>`, but its
LL | struct S<A, B>(A, B); LL | struct S<A, B>(A, B);
| -------------- associated item `X` not found for this struct | -------------- associated item `X` not found for this struct
LL | struct Featureless; LL | struct Featureless;
| ------------------ | ------------------ doesn't satisfy `Featureless: One` or `Featureless: Two`
| |
| doesn't satisfy `Featureless: One`
| doesn't satisfy `Featureless: Two`
... ...
LL | let _: S::<Featureless, Featureless>::X; LL | let _: S::<Featureless, Featureless>::X;
| ^ associated type cannot be referenced on `S<Featureless, Featureless>` due to unsatisfied trait bounds | ^ associated type cannot be referenced on `S<Featureless, Featureless>` due to unsatisfied trait bounds