From 96c96645c7bb70a73ced2046df8fe083ad2ae3fc Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:23:56 +0200 Subject: [PATCH 1/2] Improve "associated type not found" diagnostics --- .../rustc_hir_analysis/src/astconv/errors.rs | 53 +++++++++++++++---- .../assoc-const-eq-missing.stderr | 12 +++-- ...missing-trait-bound-for-assoc-fails.stderr | 4 +- .../associated-types-path-1.stderr | 4 +- .../ui/associated-types/issue-23595-2.stderr | 2 +- tests/ui/error-codes/E0220.stderr | 2 +- ...ature-gate-return_type_notation.cfg.stderr | 4 +- ...te-return_type_notation.cfg_current.stderr | 4 +- ...-gate-return_type_notation.cfg_next.stderr | 4 +- tests/ui/lifetimes/issue-95023.stderr | 2 +- 10 files changed, 69 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 6082d446979..26bd3b0f6a9 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -110,16 +110,22 @@ pub(crate) fn complain_about_assoc_type_not_found( { // 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 @@ pub(crate) fn complain_about_assoc_type_not_found( }) .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 @@ pub(crate) fn complain_about_assoc_type_not_found( }) .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 @@ pub(crate) fn complain_about_assoc_type_not_found( } } - 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() } diff --git a/tests/ui/associated-consts/assoc-const-eq-missing.stderr b/tests/ui/associated-consts/assoc-const-eq-missing.stderr index b4bd6456c85..9cd3865fc3b 100644 --- a/tests/ui/associated-consts/assoc-const-eq-missing.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-missing.stderr @@ -2,19 +2,25 @@ error[E0220]: associated type `Z` not found for `Foo` --> $DIR/assoc-const-eq-missing.rs:15:16 | LL | fn foo1>() {} - | ^ associated type `Z` not found + | ^ + | + = help: `Foo` has no associated type, try removing `Z` error[E0220]: associated type `Z` not found for `Foo` --> $DIR/assoc-const-eq-missing.rs:17:16 | LL | fn foo2>() {} - | ^ associated type `Z` not found + | ^ + | + = help: `Foo` has no associated type, try removing `Z` error[E0220]: associated type `Z` not found for `Foo` --> $DIR/assoc-const-eq-missing.rs:19:16 | LL | fn foo3>() {} - | ^ associated type `Z` not found + | ^ + | + = help: `Foo` has no associated type, try removing `Z` error: aborting due to 3 previous errors diff --git a/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr b/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr index bc2807b0396..a964c9df2c5 100644 --- a/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr +++ b/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr @@ -8,7 +8,9 @@ error[E0220]: associated type `Item` not found for `M` --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:8 | LL | M::Item: Temp, - | ^^^^ associated type `Item` not found + | ^^^^ + | + = help: `M` has no associated type, try removing `Item` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/associated-types-path-1.stderr b/tests/ui/associated-types/associated-types-path-1.stderr index a67f77e37c7..195740359a3 100644 --- a/tests/ui/associated-types/associated-types-path-1.stderr +++ b/tests/ui/associated-types/associated-types-path-1.stderr @@ -2,7 +2,9 @@ error[E0220]: associated type `A` not found for `T` --> $DIR/associated-types-path-1.rs:10:26 | LL | pub fn f1(a: T, x: T::A) {} - | ^ associated type `A` not found + | ^ + | + = help: `T` has no associated type, try removing `A` error[E0221]: ambiguous associated type `A` in bounds of `T` --> $DIR/associated-types-path-1.rs:11:34 diff --git a/tests/ui/associated-types/issue-23595-2.stderr b/tests/ui/associated-types/issue-23595-2.stderr index dded673f6ee..73effa9f955 100644 --- a/tests/ui/associated-types/issue-23595-2.stderr +++ b/tests/ui/associated-types/issue-23595-2.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `anything_here_kills_it` not found for `Self` --> $DIR/issue-23595-2.rs:6:22 | LL | type B = C; - | ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found + | ^^^^^^^^^^^^^^^^^^^^^^ help: `Self` has the following associated type: `B` error: aborting due to previous error diff --git a/tests/ui/error-codes/E0220.stderr b/tests/ui/error-codes/E0220.stderr index 11763ce788d..e03eadacae4 100644 --- a/tests/ui/error-codes/E0220.stderr +++ b/tests/ui/error-codes/E0220.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `F` not found for `Trait` --> $DIR/E0220.rs:5:22 | LL | type Foo = dyn Trait; - | ^ associated type `F` not found + | ^ help: `Trait` has the following associated type: `Bar` error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified --> $DIR/E0220.rs:5:16 diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr index 1bdb2574ead..012913fd0e0 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -19,7 +19,9 @@ error[E0220]: associated type `m` not found for `Trait` --> $DIR/feature-gate-return_type_notation.rs:14:17 | LL | fn foo>() {} - | ^ associated type `m` not found + | ^ + | + = help: `Trait` has no associated type, try removing `m` error: aborting due to 3 previous errors diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr index ce39f6b2971..68cf8e36fcc 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr @@ -19,7 +19,9 @@ error[E0220]: associated type `m` not found for `Trait` --> $DIR/feature-gate-return_type_notation.rs:17:17 | LL | fn foo>() {} - | ^ associated type `m` not found + | ^ + | + = help: `Trait` has no associated type, try removing `m` error: aborting due to 3 previous errors diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr index ce39f6b2971..68cf8e36fcc 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr @@ -19,7 +19,9 @@ error[E0220]: associated type `m` not found for `Trait` --> $DIR/feature-gate-return_type_notation.rs:17:17 | LL | fn foo>() {} - | ^ associated type `m` not found + | ^ + | + = help: `Trait` has no associated type, try removing `m` error: aborting due to 3 previous errors diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index 5b93eff8614..6361d8ad30b 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -36,7 +36,7 @@ error[E0220]: associated type `B` not found for `Self` --> $DIR/issue-95023.rs:6:44 | LL | fn foo(&self) -> Self::B<{N}>; - | ^ associated type `B` not found + | ^ help: `Self` has the following associated type: `Output` error: aborting due to 5 previous errors From a0e0a3261e5f8d4515621d90dc2a1e377eb19483 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Fri, 8 Sep 2023 08:44:23 +0200 Subject: [PATCH 2/2] E0220: only suggests associated types if there's only one candidate --- .../rustc_hir_analysis/src/astconv/errors.rs | 44 ++++++++----------- .../assoc-const-eq-missing.stderr | 12 ++--- ...missing-trait-bound-for-assoc-fails.stderr | 4 +- .../associated-types-path-1.stderr | 4 +- ...ature-gate-return_type_notation.cfg.stderr | 4 +- ...te-return_type_notation.cfg_current.stderr | 4 +- ...-gate-return_type_notation.cfg_next.stderr | 4 +- 7 files changed, 27 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 26bd3b0f6a9..ed4dde419c4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -201,34 +201,28 @@ pub(crate) fn complain_about_assoc_type_not_found( } } - // If we still couldn't find any associated type, just list them all. + // If we still couldn't find any associated type, and only one associated type exists, + // suggests using it. - if all_candidate_names.is_empty() { - err.help(format!( - "`{ty_param_name}` has no associated type, try removing `{assoc_name}`" - )); - return err.emit(); + if all_candidate_names.len() == 1 { + // this should still compile, except on `#![feature(associated_type_defaults)]` + // where it could suggests `type A = Self::A`, thus recursing infinitely + let applicability = if self.tcx().features().associated_type_defaults { + Applicability::Unspecified + } else { + Applicability::MaybeIncorrect + }; + + err.span_suggestion( + assoc_name.span, + format!("`{ty_param_name}` has the following associated type"), + all_candidate_names.first().unwrap().to_string(), + applicability, + ); + } else { + err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found")); } - 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() } diff --git a/tests/ui/associated-consts/assoc-const-eq-missing.stderr b/tests/ui/associated-consts/assoc-const-eq-missing.stderr index 9cd3865fc3b..b4bd6456c85 100644 --- a/tests/ui/associated-consts/assoc-const-eq-missing.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-missing.stderr @@ -2,25 +2,19 @@ error[E0220]: associated type `Z` not found for `Foo` --> $DIR/assoc-const-eq-missing.rs:15:16 | LL | fn foo1>() {} - | ^ - | - = help: `Foo` has no associated type, try removing `Z` + | ^ associated type `Z` not found error[E0220]: associated type `Z` not found for `Foo` --> $DIR/assoc-const-eq-missing.rs:17:16 | LL | fn foo2>() {} - | ^ - | - = help: `Foo` has no associated type, try removing `Z` + | ^ associated type `Z` not found error[E0220]: associated type `Z` not found for `Foo` --> $DIR/assoc-const-eq-missing.rs:19:16 | LL | fn foo3>() {} - | ^ - | - = help: `Foo` has no associated type, try removing `Z` + | ^ associated type `Z` not found error: aborting due to 3 previous errors diff --git a/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr b/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr index a964c9df2c5..bc2807b0396 100644 --- a/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr +++ b/tests/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr @@ -8,9 +8,7 @@ error[E0220]: associated type `Item` not found for `M` --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:8 | LL | M::Item: Temp, - | ^^^^ - | - = help: `M` has no associated type, try removing `Item` + | ^^^^ associated type `Item` not found error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/associated-types-path-1.stderr b/tests/ui/associated-types/associated-types-path-1.stderr index 195740359a3..a67f77e37c7 100644 --- a/tests/ui/associated-types/associated-types-path-1.stderr +++ b/tests/ui/associated-types/associated-types-path-1.stderr @@ -2,9 +2,7 @@ error[E0220]: associated type `A` not found for `T` --> $DIR/associated-types-path-1.rs:10:26 | LL | pub fn f1(a: T, x: T::A) {} - | ^ - | - = help: `T` has no associated type, try removing `A` + | ^ associated type `A` not found error[E0221]: ambiguous associated type `A` in bounds of `T` --> $DIR/associated-types-path-1.rs:11:34 diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr index 012913fd0e0..1bdb2574ead 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -19,9 +19,7 @@ error[E0220]: associated type `m` not found for `Trait` --> $DIR/feature-gate-return_type_notation.rs:14:17 | LL | fn foo>() {} - | ^ - | - = help: `Trait` has no associated type, try removing `m` + | ^ associated type `m` not found error: aborting due to 3 previous errors diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr index 68cf8e36fcc..ce39f6b2971 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr @@ -19,9 +19,7 @@ error[E0220]: associated type `m` not found for `Trait` --> $DIR/feature-gate-return_type_notation.rs:17:17 | LL | fn foo>() {} - | ^ - | - = help: `Trait` has no associated type, try removing `m` + | ^ associated type `m` not found error: aborting due to 3 previous errors diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr index 68cf8e36fcc..ce39f6b2971 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr @@ -19,9 +19,7 @@ error[E0220]: associated type `m` not found for `Trait` --> $DIR/feature-gate-return_type_notation.rs:17:17 | LL | fn foo>() {} - | ^ - | - = help: `Trait` has no associated type, try removing `m` + | ^ associated type `m` not found error: aborting due to 3 previous errors