Suggest trait bounds for used associated type on type param

Fix #101351.

When an associated type on a type parameter is used, and the type
parameter isn't constrained by the correct trait, suggest the
appropriate trait bound:

```
error[E0220]: associated type `Associated` not found for `T`
 --> file.rs:6:15
  |
6 |     field: T::Associated,
  |               ^^^^^^^^^^ there is a similarly named associated type `Associated` in the trait `Foo`
  |
help: consider restricting type parameter `T`
  |
5 | struct Generic<T: Foo> {
  |                 +++++
  ```

When an associated type on a type parameter has a typo, suggest fixing
it:

```
error[E0220]: associated type `Baa` not found for `T`
  --> $DIR/issue-55673.rs:9:8
   |
LL |     T::Baa: std::fmt::Debug,
   |        ^^^ there is a similarly named associated type `Bar` in the trait `Foo`
   |
help: change the associated type name to use `Bar` from `Foo`
   |
LL |     T::Bar: std::fmt::Debug,
   |        ~~~
```
This commit is contained in:
Esteban Küber
2023-09-29 03:16:11 +00:00
parent df4379b4eb
commit 781e86477c
11 changed files with 147 additions and 19 deletions

View File

@@ -1061,6 +1061,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
},
param_name,
Some(ty_param_def_id),
assoc_name,
span,
None,
@@ -1074,6 +1075,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
all_candidates: impl Fn() -> I,
ty_param_name: impl Display,
ty_param_def_id: Option<LocalDefId>,
assoc_name: Ident,
span: Span,
is_equality: Option<ty::Term<'tcx>>,
@@ -1095,6 +1097,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let reported = self.complain_about_assoc_type_not_found(
all_candidates,
&ty_param_name.to_string(),
ty_param_def_id,
assoc_name,
span,
);
@@ -1142,30 +1145,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_label(
bound_span,
format!(
"ambiguous `{}` from `{}`",
assoc_name,
"ambiguous `{assoc_name}` from `{}`",
bound.print_only_trait_path(),
),
);
if let Some(constraint) = &is_equality {
where_bounds.push(format!(
" T: {trait}::{assoc} = {constraint}",
" T: {trait}::{assoc_name} = {constraint}",
trait=bound.print_only_trait_path(),
assoc=assoc_name,
constraint=constraint,
));
} else {
err.span_suggestion_verbose(
span.with_hi(assoc_name.span.lo()),
"use fully qualified syntax to disambiguate",
format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()),
format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()),
Applicability::MaybeIncorrect,
);
}
} else {
err.note(format!(
"associated type `{}` could derive from `{}`",
ty_param_name,
"associated type `{ty_param_name}` could derive from `{}`",
bound.print_only_trait_path(),
));
}
@@ -1173,8 +1172,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if !where_bounds.is_empty() {
err.help(format!(
"consider introducing a new type parameter `T` and adding `where` constraints:\
\n where\n T: {},\n{}",
ty_param_name,
\n where\n T: {ty_param_name},\n{}",
where_bounds.join(",\n"),
));
}
@@ -1396,6 +1394,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
},
kw::SelfUpper,
None,
assoc_ident,
span,
None,