-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trait impls from where clauses (ParamEnv
) take precedence over freestanding trait impls
#24066
Comments
@nikomatsakis Is this not a bug? It seems to be the feature that was discussed in #33108 of lifting trait methods to inherent methods. |
I would say this is... a grey area. Perhaps a known shortcoming would be the best description. The trait selection algorithm definitely prefers where clauses to impls when there is inference involved -- this often is crucial to making progress, but here creates a problem. You could probably workaround it by adding some (redundant) where-clauses like where |
Here's a simple example of what I think is the same bug:
This is definitely a problem. |
The example in the issue description now compiles. Closing. |
Not again, I tested in the wrong directory. Re-opening.... |
"Me too" — play example — forum. |
…atsakis Re-enable trivial bounds cc #50825 Remove implementations from global bounds in winnowing when there is ambiguity. This results in the reverse of #24066 happening sometimes. I'm not sure if anything can be done about that though. cc #48214 r? @nikomatsakis
Small example to illustrate the problem (I do velieve it caused by the same bug): fn f<V>(_: V) -> String
where
String: From<V>,
{
From::from("Hello") // works
String::from("Hello") // doesn't work
} |
One thing I noted while investigating a related issue also applies to @Pzixel's example above, where adding another trait bound can fix the problem in strange ways. The type parameter of the generic trait in the extra bound can be another generic type parameter or an HRTB with a concrete type, but not another concrete type. Here is more (confusing) food for thought as of fn ok_with_another_bound_generic<V, W>() -> String
where
String: From<V> + From<W>,
{
String::from("✅")
}
fn nok_with_another_bound_concrete<V>() -> String
where
String: From<V> + From<char>,
{
String::from("❌")
}
fn ok_with_another_bound_concrete_hrtb<V>() -> String
where
String: From<V> + for<'a> From<&'a String>,
{
String::from("✅")
}
fn nok_with_another_bound_concrete_expected_type<V>() -> String
where
String: From<V> + From<&'static str>,
{
String::from("❌")
}
fn ok_with_another_bound_concrete_expected_type_local_trait<V>() -> String
where
String: MyFrom<V> + MyFrom<&'static str>,
{
String::my_from("✅")
}
fn ok_with_another_bound_concrete_expected_type_local_type<V>() -> MyString
where
MyString: From<V> + From<&'static str>,
{
MyString::from("✅")
}
trait MyFrom<T> { fn my_from(_: T) -> Self; }
impl<T> MyFrom<T> for T { fn my_from(x: T) -> Self { x } }
impl MyFrom<&str> for String { fn my_from(c: &str) -> Self { c.into() } }
struct MyString;
impl From<&str> for MyString { fn from(_: &str) -> Self { MyString } } |
ParamEnv
) take precedence over freestanding trait impls
ParamEnv
) take precedence over freestanding trait implsParamEnv
) take precedence over freestanding trait impls
I think I ran into the same problem with some code that I reduced to: use std::ops::Mul;
#[derive(Debug)]
struct UsizeWrapper(usize);
impl Mul<UsizeWrapper> for usize {
type Output = UsizeWrapper;
fn mul(self, rhs: UsizeWrapper) -> Self::Output {
UsizeWrapper(self * rhs.0)
}
}
fn mul_6<T>(v: T) -> T
where
usize: Mul<T, Output = T>,
{
// Doesn't work:
2usize * 3usize * v
// Works:
//6usize * v
}
fn main() {
println!("{:?}", mul_6(UsizeWrapper(10usize)));
} Error:
|
I stumbled upon this trying to write a function that generically takes a range (or something else with which
str
can be indexed), and slices a str with that range. I got that to work, this bug comes into play when the str is produced by slicing another string with aRangeFrom
or another concrete type (in the same function).Here's a simpler (no lifetimes, no associated types) and self-contained example (playpen):
This seems innocent enough. There's a
impl Frobnicate<IA> for Thing
, so the.frob(IA)
call should work, and it's known to returnThing
again, so via thewhere
clause the.frob(i)
call is good as well. However, I get this error message:It appears that the where clause makes the compiler forget that there are other impls.
Adding a
Thing : Frobnicate<IA>
bound only makes the compiler (rightly) complain that that's not a bound at all, since it doesn't involve any type parameters.UFCS makes it compile, though:
Edit: Besides playpen, I can also reproduce this locally:
But I already noticed it a couple of weeks ago, so it can't be a recent regression.
The text was updated successfully, but these errors were encountered: