Confusing error message when trait is impl'd on &T and bounds are not satisfied
Example code: https://play.rust-lang.org/?gist=6e7c1a4ad58c82717271ad4d5cef1181&version=stable
The form that I encountered was:
error[E0277]: the trait bound `&Ident: std::cmp::PartialEq<str>` is not satisfied
--> src/main.rs:22:18
|
22 | if ident.eq( "STRING" ) {
| ^^ can't compare `&Ident` with `str`
|
= help: the trait `std::cmp::PartialEq<str>` is not implemented for `&Ident`
syn::Ident implements PartialEq<T> where T: AsRef<str> so I know I can compare Ident with a str.
My first reaction was confusion with str. It's so rare to see str alone that my first instinct was to ensure that what I have is &str. While still confused, I decided to throw an & in front of my parameter. To my surprise that fixed the error!
... but now I was even more confused. ident.eq( &"Static string" ) looks a bit weird - and why would it even make a difference?
After a while I realized that my ident was a ref of &Ident - so essentially a double-borrowed &&Ident. But as Rust has auto-(de)ref for method calls, this shouldn't matter. I've had &&&...Foo types in the past by being overly eager with &'s and these have worked just fine without needing any manual *'s.
However I've now concluded that the problem here is the built-in impl PartialEq<&B> for &A.
With let ident : &&Ident, the ident.eq(..) gets resolved to:
impl<'a, 'b, A (&Ident), B = ?>PartialEq<&B> for &A
where A (&Ident) : PartialEq<B> {
fn eq( &self, other: &B ) -> bool;
}
Where B ends up as str to make the eq(..) signature match &str. Thus the error.
In any case the biggest issue here is the "friendly" error message, I feel: can't compare '&Ident' with 'str'. Both types here seem wrong.
- On the right side as far as I can tell,
"STRING"is&str, notstr. - On the left side the type should be
&&Ident, not an&Ident.
I guess the parameters are wrong, because Rust does one cycle of derefs. The original types are &&Ident and &str, but the impl above drops one & from each of these.
What purpose does the PartialEq<&B> for &A impl serve anyway? If that impl didn't exist, wouldn't rustc do derefs for &&&A until it found impl for A? Then it would deref the argument. Or is this unwanted behavior in this scenario - even if this is how the auto-deref works everywhere else? Or ~~am I missing~~ I am probably missing some other detail that prevents this from working.
Current error:
error[[E0277]](https://doc.rust-lang.org/stable/error_codes/E0277.html): can't compare `&S` with `S` --> src/main.rs:29:15 | 29 | (&&s).eq( &o ); // This fails. Trait resolution doesn't auto deref? | -- ^^ no implementation for `&S == S` | | | required by a bound introduced by this call | = help: the trait `PartialEq<S>` is not implemented for `&S` help: consider removing the leading `&`-reference | 29 - (&&s).eq( &o ); // This fails. Trait resolution doesn't auto deref? 29 + (&&s).eq( o ); // This fails. Trait resolution doesn't auto deref? | For more information about this error, try `rustc --explain E0277`.Dylan DPC at 2023-06-23 17:07:02