-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Invalid collision with TryFrom implementation? #50133
Comments
Ran into this issue as well. In my case: use std::ffi::OsStr;
use std::path::PathBuf;
use std::io;
#[derive(Clone)]
pub struct DataSet {
pub path: PathBuf,
pub mountpoint: PathBuf,
}
pub fn get_mountpoint<P: AsRef<OsStr>>(path: P) -> Result<String, io::Error> {
// ...
}
impl<P> TryFrom<P> for DataSet
where P: AsRef<OsStr>
{
type Error = io::Error;
fn try_from(path: P) -> Result<Self, Self::Error> {
let mountpoint: String = get_mountpoint(&path)?;
let mountpoint = PathBuf::from(mountpoint);
let path = path.as_ref().to_path_buf();
Ok(Self { path, mountpoint })
}
} Error: error[E0119]: conflicting implementations of trait `std::convert::TryFrom<_>` for type `<mod>::DataSet`:
--> src/<file>.rs:80:1
|
80 | / impl<P> TryFrom<P> for DataSet
81 | | where P: AsRef<OsStr>
82 | | {
83 | | type Error = io::Error;
... |
89 | | }
90 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where T: std::convert::From<U>; In this case, the |
I'm getting this issue as well on 1.34. It appears to happen any time you attempt to impl TryFrom with a bounded generic parameter (regardless of its position.) I'm not sure if this is a compiler bug or just me writing it wrong: impl<'a, I> TryFrom<I> for CStringVec
where I: Iterator<Item = &'a str>
{
type Error = Error;
/// Creates a new `CStringVec` from an iterator.
#[inline]
fn try_from(it: I) -> Result<Self, Self::Error>
{
// ...
}
}
Edit: This is not a bug, although the error message potentially is one. The real issue is that you cannot implement a trait with a generic trait not from this crate. |
This is is due to this core blanket implementation. Since it is possible that a type implement both the core Not sure how to circumvent this without negative trait bounds. edit: Updated outdated link |
This is really frustrating to work with. I have been unable to find a way to provide certain generic TryFrom impls like: impl<T: ToString> TryFrom<T> for X { ... } Collision. impl<T: AsRef<str>> TryFrom<T> for X { ... } Collision. Argh! |
I would like to add that I would love a solution for this. I constantly use the |
This really is a very painful feature to use due to the aforementioned conflict with the blanket implementation. I gather that removing the blanket implementation is a breaking change, but I can't imagine that it is something that is heavily depended on. Removing this blanket implementation would definitely make these traits more useful. |
TryFrom is implemented for '&char' instead of 'char' due to a conflict with the blanket implementation. For more details see: rust-lang/rust#50133 https://old.reddit.com/r/rust/comments/c1yubv/why_this_code_does_not_compile/
TryFrom is implemented for '&char' instead of 'char' due to a conflict with the blanket implementation. For more details see: rust-lang/rust#50133 https://old.reddit.com/r/rust/comments/c1yubv/why_this_code_does_not_compile/
TryFrom is implemented for '&char' instead of 'char' due to a conflict with the blanket implementation. For more details see: rust-lang/rust#50133 https://old.reddit.com/r/rust/comments/c1yubv/why_this_code_does_not_compile/
@jean-airoldie just wanted to clarify out of curiosity, the blanket implementation for TryInto/Into for TryFrom is this one, right? https://github.com/rust-lang/rust/blob/master/src/libcore/convert.rs#L566-L586 Figured the Rust docs link might be outdated. |
Yeah, I should have used a perma-link instead. I'll edit my comment. |
Does anyone know when/if this will be fixed? I've just stubbed my toe into it, and the only way that I can get around it is to bind to concrete types. The problem is that due to what I'm writing a newtype wrapper for, this will mean I have around 1300 essentially identical implementations for each and every newtype wrapper that I'm generating. I can write a code generator in python to speed to handle this, but that isn't ideal. |
Is this related to the problem I am having refactoring the apint crate? I am refactoring some code involving the invariant management type The reason for this is the blanket impl
Edit: I fixed the problem by adding
and a |
This is a very annoying error. Here is my workaround: if you have something like, // E0119!
impl<T> TryFrom<T> for MyType { /* */ } You can create a little wrapper struct, which I think should compile away as a zero-cost abstraction, to get around the compiler error. pub struct InputWrapper<T>(T);
impl<T> TryFrom<InputWrapper<T>> for MyType { /* */ } By removing the raw templatized parameter on the TryFrom, you can circumvent E0119. To use it, you just need to wrap the variable in MyType::try_from(InputWrapper(foo)) I hope that the problem can be somehow fixed upstream to avoid needing workarounds like this. |
Would it be an option to insert a marker trait (empty trait with a distinct_and_long_name) that is a bound to the blanket implementation of the stdlib? That way people could opt in to this blanket if they need it without making it completely impossible to have generic |
Anyone know how this is going? I'm trying to clean up my code, and it isn't going well because of this bug. |
Does it make sense to let the compiler prefer a more strict implementation than looser one? For example, when two implementation of the same trait on a potentially conflict type, choose the more restricted one rather than preventing a new implementation. Lets say we implement |
@cmpute As I understand it, you've just described the specialization feature that has been on nightly since forever. It exists, but (again, as I understand it), there are issues that have so far prevented it from landing on stable. |
This does require the removal of the From implementation; it couldn't be converted to TryFrom due to lack of generic specialization (rust-lang/rust#50133). Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
This does require the removal of the From implementation; it couldn't be converted to TryFrom due to lack of generic specialization (rust-lang/rust#50133). Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
This does require the removal of the From implementation; it couldn't be converted to TryFrom due to lack of generic specialization (rust-lang/rust#50133). Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Why does this receive so little attention? This is a big usability problem affecting the whole trait system. |
@leontepe You can try talking about changing this starting in Rust 2024. It probably wouldn't be changed by then, but a deprecation warning could be issued for the blanket implementation that is the cause of this problem, and then it could be removed in Rust 2027. However, since it is a part of stable Rust, removing it or changing it could be very, very hard to do. I think that's the reason no-one has tried to do so yet; it's an annoying wart, but not something that breaks the safe/unsafe separation, or causes critical breakage, so no-one has put in the effort to make the change. |
I believe I also just issue in a multi-crate project:
and then in another crate:
It would indeed be very useful to be able to do this - as it guarantees the implemented tuple-type on some core-library-entity is of the same type as implemented in a consuming application or library. I can work around it by exposing the a
|
Can the language team be persuaded to prove their hypothesis that dropping the blanket implementation would break real, intentional code in the wild? It's fine if it does, but does it really? |
Just for this trait, make an exception, allow people to redefine |
@criloz I understand where you're coming from, but trust me, special casing something like |
For some reason I cannot have an implementation for TryFrom and From in the same file:
I am new to Rust but looking at some other comments, it seems that something kinda |
@AAlvarez90, the |
The compiler now emits a different error for the original code. I think the old error was misleading, and the blanket
For an explanation of why these rules exist and how they came to be, see https://smallcultfollowing.com/babysteps/blog/2015/01/14/little-orphan-impls/. |
I hope this will be dealt with soon. Now I have to write like this. struct A {}
trait B {}
struct Wrapper<T>(T);
impl<T: B> TryFrom<Wrapper<T>> for A {
type Error = ();
fn try_from(value: Wrapper<T>) -> Result<Self, Self::Error> {
let value = value.0;
todo!()
}
} Now I find I have to use Another solution is use a Builder type or use |
Sorry for the code dump. This is the smallest code I could make to reproduce the problem.
Attempting to compile this produces:
I've spent several hours looking at this and I can't figure out why I'm getting these errors. The type parameter
A
is being used as the type parameter for a local type. Maybe the compiler can't tell because it is nested insideTryFrom<>
?But I'm also not sure why the first error occurs at all. The rule it conflicts with can basically be described as "types with infallible conversions implicitly implement fallible conversions." But in my case there is no infallible conversion. So I don't see where the conflict is arising from.
If there is really a bug and I'm not just overtired, this may impact #49305.
The text was updated successfully, but these errors were encountered: