From 27d5db166e8e640ab8317cc96b91ffe60270b6c5 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 11 Jul 2024 08:14:28 +0200 Subject: [PATCH] Allows `#[diagnostic::do_not_recommend]` to supress trait impls in suggestions as well This commit changes the error reporting mechanism for not implemented traits to skip impl marked as `#[diagnostic::do_not_recommend]` in the help part of the error message ("the following other types implement trait `Foo`:"). The main use case here is to allow crate authors to skip non-meaningful confusing suggestions. A common example for this are fully generic impls on tuples. --- .../traits/fulfillment_errors.rs | 19 ++++++++++++++ ...supress_suggestions_in_help.current.stderr | 18 +++++++++++++ .../supress_suggestions_in_help.next.stderr | 18 +++++++++++++ .../supress_suggestions_in_help.rs | 25 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index f7ec5f1ff325f..2e6247b46401d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1776,6 +1776,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true }; + // we filter before checking if `impl_candidates` is empty + // to get the fallback solution if we filtered out any impls + let impl_candidates = impl_candidates + .into_iter() + .cloned() + .filter(|cand| { + !self.tcx.has_attrs_with_path( + cand.impl_def_id, + &[sym::diagnostic, sym::do_not_recommend], + ) + }) + .collect::>(); + let def_id = trait_ref.def_id(); if impl_candidates.is_empty() { if self.tcx.trait_is_auto(def_id) @@ -1788,6 +1801,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut impl_candidates: Vec<_> = self .tcx .all_impls(def_id) + // ignore `do_not_recommend` items + .filter(|def_id| { + !self + .tcx + .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend]) + }) // Ignore automatically derived impls and `!Trait` impls. .filter_map(|def_id| self.tcx.impl_trait_header(def_id)) .filter_map(|header| { diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr new file mode 100644 index 0000000000000..629fc59361dd2 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/supress_suggestions_in_help.rs:23:11 + | +LL | check(()); + | ----- ^^ the trait `Foo` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required by a bound in `check` + --> $DIR/supress_suggestions_in_help.rs:20:18 + | +LL | fn check(a: impl Foo) {} + | ^^^ required by this bound in `check` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr new file mode 100644 index 0000000000000..629fc59361dd2 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/supress_suggestions_in_help.rs:23:11 + | +LL | check(()); + | ----- ^^ the trait `Foo` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required by a bound in `check` + --> $DIR/supress_suggestions_in_help.rs:20:18 + | +LL | fn check(a: impl Foo) {} + | ^^^ required by this bound in `check` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs new file mode 100644 index 0000000000000..ef6f255c3518b --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(do_not_recommend)] + +trait Foo {} + +#[diagnostic::do_not_recommend] +impl Foo for (A,) {} + +#[diagnostic::do_not_recommend] +impl Foo for (A, B) {} + +#[diagnostic::do_not_recommend] +impl Foo for (A, B, C) {} + +impl Foo for i32 {} + +fn check(a: impl Foo) {} + +fn main() { + check(()); + //~^ ERROR the trait bound `(): Foo` is not satisfied +}