Improve "associated type not found" diagnostics

This commit is contained in:
Lieselotte 2023-09-08 06:23:56 +02:00
parent 1e746d7741
commit 96c96645c7
No known key found for this signature in database
GPG key ID: 43A6A32F83A6F9B1
10 changed files with 69 additions and 22 deletions

View file

@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
// valid span, so we point at the whole path segment instead.
let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
let is_dummy = assoc_name.span == DUMMY_SP;
let mut err = struct_span_err!(
self.tcx().sess,
span,
if is_dummy { span } else { assoc_name.span },
E0220,
"associated type `{}` not found for `{}`",
assoc_name,
ty_param_name
);
if is_dummy {
err.span_label(span, format!("associated type `{assoc_name}` not found"));
return err.emit();
}
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect();
if let (Some(suggested_name), true) = (
find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
assoc_name.span != DUMMY_SP,
) {
if let Some(suggested_name) =
find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
{
err.span_suggestion(
assoc_name.span,
"there is an associated type with a similar name",
@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect();
if let (Some(suggested_name), true) = (
find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
assoc_name.span != DUMMY_SP,
) {
if let Some(suggested_name) =
find_best_match_for_name(&wider_candidate_names, assoc_name.name, None)
{
if let [best_trait] = visible_traits
.iter()
.filter(|trait_def_id| {
@ -197,7 +201,34 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
err.span_label(span, format!("associated type `{assoc_name}` not found"));
// If we still couldn't find any associated type, just list them all.
if all_candidate_names.is_empty() {
err.help(format!(
"`{ty_param_name}` has no associated type, try removing `{assoc_name}`"
));
return err.emit();
}
let msg = if all_candidate_names.len() > 1 {
format!("`{ty_param_name}` has the following associated types")
} else {
format!("`{ty_param_name}` has the following associated type")
};
let applicability = if self.tcx().features().associated_type_defaults {
Applicability::Unspecified // `type A = Self::B` would suggest `type A = Self::A`
} else {
Applicability::MaybeIncorrect
};
err.span_suggestions(
assoc_name.span,
msg,
all_candidate_names.iter().map(|symbol| symbol.to_string()),
applicability,
);
err.emit()
}