Skip to content

Commit de346ad

Browse files
committed
Rewrite do_not_recommend example
This rewrites the example to use a more realistic example that actually demonstrates an improvement in the error message.
1 parent 341cc83 commit de346ad

File tree

1 file changed

+78
-34
lines changed

1 file changed

+78
-34
lines changed

src/attributes/diagnostics.md

+78-34
Original file line numberDiff line numberDiff line change
@@ -576,58 +576,102 @@ The attribute should be placed on a [trait implementation item][trait-impl], tho
576576
r[attributes.diagnostic.do_not_recommend.syntax]
577577
The attribute does not accept any arguments, though unexpected arguments are not considered as an error.
578578

579-
In this example,
579+
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`.
580580

581581
```rust,compile_fail,E0277
582-
trait Foo {}
583-
584-
impl<T> Foo for T where T: Send {}
582+
# pub trait Expression {
583+
# type SqlType;
584+
# }
585+
#
586+
# pub trait AsExpression<ST> {
587+
# type Expression: Expression<SqlType = ST>;
588+
# }
589+
#
590+
# pub struct Text;
591+
# pub struct Integer;
592+
#
593+
# pub struct Bound<T>(T);
594+
# pub struct SelectInt;
595+
#
596+
# impl Expression for SelectInt {
597+
# type SqlType = Integer;
598+
# }
599+
#
600+
# impl<T> Expression for Bound<T> {
601+
# type SqlType = T;
602+
# }
603+
#
604+
# impl AsExpression<Integer> for i32 {
605+
# type Expression = Bound<Integer>;
606+
# }
607+
#
608+
# impl AsExpression<Text> for &'_ str {
609+
# type Expression = Bound<Text>;
610+
# }
611+
#
612+
# impl<T> Foo for T where T: Expression {}
613+
614+
// Uncomment this line to change the recommendation.
615+
// #[diagnostic::do_not_recommend]
616+
impl<T, ST> AsExpression<ST> for T
617+
where
618+
T: Expression<SqlType = ST>,
619+
{
620+
type Expression = T;
621+
}
585622
586-
fn needs_foo<T: Foo>() {}
623+
trait Foo: Expression + Sized {
624+
fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
625+
where
626+
T: AsExpression<Self::SqlType>,
627+
{
628+
todo!()
629+
}
630+
}
587631
588632
fn main() {
589-
// Mutable pointers do not implement `Send`, so this will not work.
590-
needs_foo::<*mut ()>();
633+
SelectInt.check("bar");
591634
}
592635
```
593636

594-
the compiler may generate an error message about the `Send` bound in the impl which looks like this:
637+
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:
595638

596639
```text
597-
error[E0277]: the trait bound `*mut (): Foo` is not satisfied
598-
--> src/main.rs:9:17
599-
|
600-
9 | needs_foo::<*mut ()>();
601-
| ^^^^^^^ the trait `Send` is not implemented for `*mut ()`
602-
|
603-
note: required for `*mut ()` to implement `Foo`
604-
--> src/main.rs:3:9
605-
|
606-
3 | impl<T> Foo for T where T: Send {}
607-
| ^^^ ^ ---- unsatisfied trait bound introduced here
608-
note: required by a bound in `needs_foo`
609-
--> src/main.rs:5:17
610-
|
611-
5 | fn needs_foo<T: Foo>() {}
612-
| ^^^ required by this bound in `needs_foo`
640+
error[E0277]: the trait bound `&str: Expression` is not satisfied
641+
--> src/main.rs:53:15
642+
|
643+
53 | SelectInt.check("bar");
644+
| ^^^^^ the trait `Expression` is not implemented for `&str`
645+
|
646+
= help: the following other types implement trait `Expression`:
647+
Bound<T>
648+
SelectInt
649+
note: required for `&str` to implement `AsExpression<Integer>`
650+
--> src/main.rs:45:13
651+
|
652+
45 | impl<T, ST> AsExpression<ST> for T
653+
| ^^^^^^^^^^^^^^^^ ^
654+
46 | where
655+
47 | T: Expression<SqlType = ST>,
656+
| ------------------------ unsatisfied trait bound introduced here
613657
```
614658

615-
By adding the `#[diagnostic::do_no_recommend]` attribute to the `impl`, the message would no longer suggest it:
659+
By adding the `#[diagnostic::do_no_recommend]` attribute to the blanket `impl` for `AsExpression`, the message changes to:
616660

617661
```text
618-
error[E0277]: the trait bound `*mut (): Foo` is not satisfied
619-
--> src/main.rs:11:17
662+
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
663+
--> src/main.rs:53:15
620664
|
621-
11 | needs_foo::<*mut ()>();
622-
| ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
665+
53 | SelectInt.check("bar");
666+
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
623667
|
624-
note: required by a bound in `needs_foo`
625-
--> src/main.rs:7:17
626-
|
627-
7 | fn needs_foo<T: Foo>() {}
628-
| ^^^ required by this bound in `needs_foo`
668+
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
669+
but trait `AsExpression<Text>` is implemented for it
670+
= help: for that trait implementation, expected `Text`, found `Integer`
629671
```
630672

673+
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_no_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`.
674+
631675
[Clippy]: https://github.com/rust-lang/rust-clippy
632676
[_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax
633677
[_MetaListPaths_]: ../attributes.md#meta-item-attribute-syntax

0 commit comments

Comments
 (0)