From 9afbbf664b9cf0f0204d966fb27d60d3a654576d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 18 Jun 2025 16:12:41 -0700 Subject: [PATCH 1/6] Adjust do_not_recommend intro to use the attribute template --- src/attributes/diagnostics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index fff0f3d632..7d9c30d665 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -553,7 +553,7 @@ r[attributes.diagnostic.do_not_recommend] ### The `diagnostic::do_not_recommend` attribute r[attributes.diagnostic.do_not_recommend.intro] -The `#[diagnostic::do_not_recommend]` attribute is a hint to the compiler to not show the annotated trait implementation as part of a diagnostic message. +The *`diagnostic::do_not_recommend` [attribute][attributes]* is a hint to the compiler to not show the annotated trait implementation as part of a diagnostic message. > [!NOTE] > Suppressing the recommendation can be useful if you know that the recommendation would normally not be useful to the programmer. This often occurs with broad, blanket impls. The recommendation may send the programmer down the wrong path, or the trait implementation may be an internal detail that you don't want to expose, or the bounds may not be able to be satisfied by the programmer. From 43a7cb2fb25f6025d2e0503946cc0be3cba5232f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 18 Jun 2025 16:14:54 -0700 Subject: [PATCH 2/6] Move do_not_recommend example to the intro --- src/attributes/diagnostics.md | 193 +++++++++++++++++----------------- 1 file changed, 97 insertions(+), 96 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 7d9c30d665..402864dd37 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -555,6 +555,103 @@ r[attributes.diagnostic.do_not_recommend] r[attributes.diagnostic.do_not_recommend.intro] The *`diagnostic::do_not_recommend` [attribute][attributes]* is a hint to the compiler to not show the annotated trait implementation as part of a diagnostic message. +> [!EXAMPLE] +> In the following example, there is a trait called `AsExpression` which is used for casting arbitrary types to the `Expression` type used in an SQL library. There is a method called `check` which takes an `AsExpression`. +> +> ```rust,compile_fail,E0277 +> # pub trait Expression { +> # type SqlType; +> # } +> # +> # pub trait AsExpression { +> # type Expression: Expression; +> # } +> # +> # pub struct Text; +> # pub struct Integer; +> # +> # pub struct Bound(T); +> # pub struct SelectInt; +> # +> # impl Expression for SelectInt { +> # type SqlType = Integer; +> # } +> # +> # impl Expression for Bound { +> # type SqlType = T; +> # } +> # +> # impl AsExpression for i32 { +> # type Expression = Bound; +> # } +> # +> # impl AsExpression for &'_ str { +> # type Expression = Bound; +> # } +> # +> # impl Foo for T where T: Expression {} +> +> // Uncomment this line to change the recommendation. +> // #[diagnostic::do_not_recommend] +> impl AsExpression for T +> where +> T: Expression, +> { +> type Expression = T; +> } +> +> trait Foo: Expression + Sized { +> fn check(&self, _: T) -> ::SqlType>>::Expression +> where +> T: AsExpression, +> { +> todo!() +> } +> } +> +> fn main() { +> SelectInt.check("bar"); +> } +> ``` +> +> The `SelectInt` type's `check` method is expecting an `Integer` type. Calling it with an i32 type works, as it gets converted to an `Integer` by the `AsExpression` trait. However, calling it with a string does not, and generates a an error that may look like this: +> +> ```text +> error[E0277]: the trait bound `&str: Expression` is not satisfied +> --> src/main.rs:53:15 +> | +> 53 | SelectInt.check("bar"); +> | ^^^^^ the trait `Expression` is not implemented for `&str` +> | +> = help: the following other types implement trait `Expression`: +> Bound +> SelectInt +> note: required for `&str` to implement `AsExpression` +> --> src/main.rs:45:13 +> | +> 45 | impl AsExpression for T +> | ^^^^^^^^^^^^^^^^ ^ +> 46 | where +> 47 | T: Expression, +> | ------------------------ unsatisfied trait bound introduced here +> ``` +> +> By adding the `#[diagnostic::do_not_recommend]` attribute to the blanket `impl` for `AsExpression`, the message changes to: +> +> ```text +> error[E0277]: the trait bound `&str: AsExpression` is not satisfied +> --> src/main.rs:53:15 +> | +> 53 | SelectInt.check("bar"); +> | ^^^^^ the trait `AsExpression` is not implemented for `&str` +> | +> = help: the trait `AsExpression` is not implemented for `&str` +> but trait `AsExpression` is implemented for it +> = help: for that trait implementation, expected `Text`, found `Integer` +> ``` +> +> The first error message includes a somewhat confusing error message about the relationship of `&str` and `Expression`, as well as the unsatisfied trait bound in the blanket impl. After adding `#[diagnostic::do_not_recommend]`, it no longer considers the blanket impl for the recommendation. The message should be a little clearer, with an indication that a string cannot be converted to an `Integer`. + > [!NOTE] > Suppressing the recommendation can be useful if you know that the recommendation would normally not be useful to the programmer. This often occurs with broad, blanket impls. The recommendation may send the programmer down the wrong path, or the trait implementation may be an internal detail that you don't want to expose, or the bounds may not be able to be satisfied by the programmer. > @@ -566,102 +663,6 @@ The attribute should be placed on a [trait implementation item][trait-impl], tho r[attributes.diagnostic.do_not_recommend.syntax] The attribute does not accept any arguments, though unexpected arguments are not considered as an error. -In the following example, there is a trait called `AsExpression` which is used for casting arbitrary types to the `Expression` type used in an SQL library. There is a method called `check` which takes an `AsExpression`. - -```rust,compile_fail,E0277 -# pub trait Expression { -# type SqlType; -# } -# -# pub trait AsExpression { -# type Expression: Expression; -# } -# -# pub struct Text; -# pub struct Integer; -# -# pub struct Bound(T); -# pub struct SelectInt; -# -# impl Expression for SelectInt { -# type SqlType = Integer; -# } -# -# impl Expression for Bound { -# type SqlType = T; -# } -# -# impl AsExpression for i32 { -# type Expression = Bound; -# } -# -# impl AsExpression for &'_ str { -# type Expression = Bound; -# } -# -# impl Foo for T where T: Expression {} - -// Uncomment this line to change the recommendation. -// #[diagnostic::do_not_recommend] -impl AsExpression for T -where - T: Expression, -{ - type Expression = T; -} - -trait Foo: Expression + Sized { - fn check(&self, _: T) -> ::SqlType>>::Expression - where - T: AsExpression, - { - todo!() - } -} - -fn main() { - SelectInt.check("bar"); -} -``` - -The `SelectInt` type's `check` method is expecting an `Integer` type. Calling it with an i32 type works, as it gets converted to an `Integer` by the `AsExpression` trait. However, calling it with a string does not, and generates a an error that may look like this: - -```text -error[E0277]: the trait bound `&str: Expression` is not satisfied - --> src/main.rs:53:15 - | -53 | SelectInt.check("bar"); - | ^^^^^ the trait `Expression` is not implemented for `&str` - | - = help: the following other types implement trait `Expression`: - Bound - SelectInt -note: required for `&str` to implement `AsExpression` - --> src/main.rs:45:13 - | -45 | impl AsExpression for T - | ^^^^^^^^^^^^^^^^ ^ -46 | where -47 | T: Expression, - | ------------------------ unsatisfied trait bound introduced here -``` - -By adding the `#[diagnostic::do_not_recommend]` attribute to the blanket `impl` for `AsExpression`, the message changes to: - -```text -error[E0277]: the trait bound `&str: AsExpression` is not satisfied - --> src/main.rs:53:15 - | -53 | SelectInt.check("bar"); - | ^^^^^ the trait `AsExpression` is not implemented for `&str` - | - = help: the trait `AsExpression` is not implemented for `&str` - but trait `AsExpression` is implemented for it - = help: for that trait implementation, expected `Text`, found `Integer` -``` - -The first error message includes a somewhat confusing error message about the relationship of `&str` and `Expression`, as well as the unsatisfied trait bound in the blanket impl. After adding `#[diagnostic::do_not_recommend]`, it no longer considers the blanket impl for the recommendation. The message should be a little clearer, with an indication that a string cannot be converted to an `Integer`. - [Clippy]: https://github.com/rust-lang/rust-clippy [`Drop`]: ../special-types-and-traits.md#drop [attributes]: ../attributes.md From 49234ba31fb26c3a5ba6761f77324f62a995679b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 18 Jun 2025 16:18:37 -0700 Subject: [PATCH 3/6] Move the do_not_recommend syntax --- src/attributes/diagnostics.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 402864dd37..28029d5464 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -657,11 +657,12 @@ The *`diagnostic::do_not_recommend` [attribute][attributes]* is a hint to the co > > For example, in an error message about a type not implementing a required trait, the compiler may find a trait implementation that would satisfy the requirements if it weren't for specific bounds in the trait implementation. The compiler may tell the user that there is an impl, but the problem is the bounds in the trait implementation. The `#[diagnostic::do_not_recommend]` attribute can be used to tell the compiler to *not* tell the user about the trait implementation, and instead simply tell the user the type doesn't implement the required trait. +r[attributes.diagnostic.do_not_recommend.syntax] +The `diagnostic::do_not_recommend` attribute does not accept any arguments, though unexpected arguments are not considered as an error. + r[attributes.diagnostic.do_not_recommend.allowed-positions] The attribute should be placed on a [trait implementation item][trait-impl], though it is not an error to be located in other positions. -r[attributes.diagnostic.do_not_recommend.syntax] -The attribute does not accept any arguments, though unexpected arguments are not considered as an error. [Clippy]: https://github.com/rust-lang/rust-clippy [`Drop`]: ../special-types-and-traits.md#drop From 8ab4b15023a85a4881f0162cacae83456cf3f761 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 18 Jun 2025 16:18:59 -0700 Subject: [PATCH 4/6] Adjust wording of attributes.diagnostic.do_not_recommend.allowed-positions Say the attribute name. --- src/attributes/diagnostics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 28029d5464..9b2c33cfa9 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -661,7 +661,7 @@ r[attributes.diagnostic.do_not_recommend.syntax] The `diagnostic::do_not_recommend` attribute does not accept any arguments, though unexpected arguments are not considered as an error. r[attributes.diagnostic.do_not_recommend.allowed-positions] -The attribute should be placed on a [trait implementation item][trait-impl], though it is not an error to be located in other positions. +The `diagnostic::do_not_recommend` attribute should be placed on a [trait implementation item][trait-impl], though it is not an error to be located in other positions. [Clippy]: https://github.com/rust-lang/rust-clippy From f0f9bcf26db85d4340f70a40cb70344fd6019009 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 18 Jun 2025 16:19:17 -0700 Subject: [PATCH 5/6] Add attributes.diagnostic.do_not_recommend.duplicates --- src/attributes/diagnostics.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 9b2c33cfa9..2809bb85c0 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -663,6 +663,8 @@ The `diagnostic::do_not_recommend` attribute does not accept any arguments, thou r[attributes.diagnostic.do_not_recommend.allowed-positions] The `diagnostic::do_not_recommend` attribute should be placed on a [trait implementation item][trait-impl], though it is not an error to be located in other positions. +r[attributes.diagnostic.do_not_recommend.duplicates] +Duplicate instances of the `diagnostic::do_not_recommend` attribute are ignored. [Clippy]: https://github.com/rust-lang/rust-clippy [`Drop`]: ../special-types-and-traits.md#drop From b68e28d61f664f6e2895d2e75ce77056ccb82990 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 22 Sep 2025 12:57:57 -0700 Subject: [PATCH 6/6] Minor update of `diagnostics::do_not_recommend` More closely align with the template, and some minor word tweaks. --- src/attributes/diagnostics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 2809bb85c0..4b88f805fa 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -549,6 +549,7 @@ error[E0277]: My Message for `ImportantTrait` implemented for `String` = note: Note 2 ``` + r[attributes.diagnostic.do_not_recommend] ### The `diagnostic::do_not_recommend` attribute @@ -664,7 +665,7 @@ r[attributes.diagnostic.do_not_recommend.allowed-positions] The `diagnostic::do_not_recommend` attribute should be placed on a [trait implementation item][trait-impl], though it is not an error to be located in other positions. r[attributes.diagnostic.do_not_recommend.duplicates] -Duplicate instances of the `diagnostic::do_not_recommend` attribute are ignored. +The `diagnostic::do_not_recommend` attribute may be used any number of times on a form. [Clippy]: https://github.com/rust-lang/rust-clippy [`Drop`]: ../special-types-and-traits.md#drop