You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Can not impl trait from another crate for Vec<T> with T from this crate #24745
In rustc 1.1.0-nightly (90cc830 2015-04-22) (built 2015-04-23):
$ rustc --crate-type lib a.rs
$ rustc -L . a.rs
a.rs:3:1: 3:28 error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
a.rs:3 impl b::Foo for Vec<Bar> {}
^~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Note the impl does not reference any types defined in this crate. This is not true, Bar is defined is this crate.
This indicates a bug either in the coherence rules (this program should be valid and the error not be shown) or in the error message, which is misleading.
I think the rationale is so that Vec<_> could be made to implement the trait later on without breaking backwards compatibility (it would conflict with your implementation of the trait otherwise).
@Diggsey by “later on”, do you mean “in a future version of the crate that defines Vec?” Ok, that’s understandable. In that case, this issue is about reformulating the error message.
If this is allowed, adding implss become a breaking-change, because any other crate could potentially have an conflicting impl. We need to bump minor version (or major version if >1.0.0) of a crate for every addition of trait impl. Moreover, as standard library is generally not allowed to make breaking-change, we can't implement existing std traits for existing std types anymore.
if your concern is the additional dependencies, you can use features.
but with From/Into. (to serialize FTL->AST->JSON and JSON->AST->FTL back).
I'm wondering if it would be possible to write code to automate the creation of a clone of a struct/enum from another crate. Then one could add Serialize/Deserialize on those local struct/enums.
Another option would be to mark structs/enums as extensible by other crates, which would allow the author to decide that he wants to let others impl features for them. That would work better in my case, because it would remove the step of converting from fluent::syntax::ast::* into fluent_json::ast::* back and forth.
I think the rationale is so that Vec<_> could be made to implement the trait later on without breaking backwards compatibility (it would conflict with your implementation of the trait otherwise).
With specialization this is not an issue anymore. If some library implements Foo for Vec<T> and I implement Foo for Vec<Bar> then with specialization both can co-exist and mine will be executed. Therefore I think that allowing implementations of traits for a type not defined in your crate but with a generic parameter from your trait could be allowed again. Do I miss another problem?
Reacted by messense, Farooq Khan, PSeitz and Fee Fladder
This indicates a bug either in the coherence rules (this program should be valid and the error not be shown) or in the error message, which is misleading.
The bug is in the error message, which I agree is misleading. It's also true that it might be nice to rejigger the rules in this area, but that's a fairly complex undertaking.
Here is a standalone test case for the same issue:
use std::fmt;structBar;impl fmt::DisplayforVec<Bar>{}fnmain(){}
Generates:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> <anon>:3:1
|
3 | impl fmt::Display for Vec<Bar> { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference any types defined in this crate
= note: define and implement a trait or new type instead
I'm not sure of the ideal wording, but one idea would be to have it highlight the "foreign types" (in this example, there is only one, the Vec type):
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> <anon>:3:1
|
3 | impl fmt::Display for Vec<Bar> { }
| ^^^^ not defined in the current crate
|
= note: define and implement a trait or new type instead
I am not sure if that last note is all that useful either. Maybe. It seems very jargon heavy.
Anyway, the trick would be getting the highlight to exclude the Bar. It may also be worth trying to comment on how Bar doesn't count because it is "under" Vec.
Would it make sense to consider type parameters' boundaries to allow anchoring / scoping impls for non-local types? e.g.
use std::fmt;structBar;traitLocalMarker{}implLocalMarkerforBar{}impl<T:LocalMarker> fmt::DisplayforVec<T>{}fnmain(){}
Reacted by Thiago Machado, Denis Kotlyarov, NOMAD, Michał Fita, Kyle Bartush, Hung-I Wang, Paulo Cesar, Pedro Ferreira, Egor Tolstonozhenko, kdxcxs and 2 more
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src/main.rs:3:1
|
3 | impl fmt::Display for Vec<Bar> { }
| ^^^^^^^^^^^^^^^^^^^^^^--------
| | |
| | `std::vec::Vec` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
For the last comment:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src/main.rs:5:1
|
5 | impl<T: LocalMarker> fmt::Display for Vec<T> { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
| | |
| | `std::vec::Vec` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
For the original report:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> b.rs:3:1
|
3 | impl a::Foo for Vec<Bar> {}
| ^^^^^^^^^^^^^^^^--------
| | |
| | `std::vec::Vec` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
@nikomatsakis is there anything else we should do here?
I know what the issue is and what the fix is, but I don't understand what "define and implement a trait or new type instead" is trying to tell me.
"define and implement a trait or new type" should presumably be "define and implement a new trait, or implement the trait on a newtype". As it's written the suggestion doesn't make sense.
Even with that alternative wording, it implies either option is feasible, but realistically creating a brand new trait is unlikely to be what the user wants. It might be worth only mentioning the newtype option, or at least listing it first.
"note: define ..." should probably be "note: consider defining ...", because actually creating a newtype or new trait may not fit with the rest of the user's program. Just "define ... instead" implies the compiler's suggestion is a drop-in replacement.
So with all that, should it instead be "consider defining a newtype and implement the trait on it instead" ?
Reacted by Esteban Kuber, Fabio Lama, Zac Ellis, Jarrod Davis and Oleg Lebedev
Activity
SimonSapin commentedon Apr 23, 2015
In either case, the work-around / fix is to make a new type that wraps
Vec<Bar>and implement the trait on that.ftxqxd commentedon Apr 23, 2015
I think this is an intentional result of #23086 (RFC 1023).
Diggsey commentedon Apr 24, 2015
I think the rationale is so that Vec<_> could be made to implement the trait later on without breaking backwards compatibility (it would conflict with your implementation of the trait otherwise).
SimonSapin commentedon Apr 24, 2015
@Diggsey by “later on”, do you mean “in a future version of the crate that defines
Vec?” Ok, that’s understandable. In that case, this issue is about reformulating the error message.Ryman commentedon Apr 25, 2016
This error now provides a link to a detailed explanation of E0117 so this issue might be considered fixed?
GildedHonour commentedon May 18, 2016
what's the reason for this restriction in the 1st place?
zbraniecki commentedon Dec 30, 2016
An example use case for this:
I have a library that implements an AST, Parser and Serializer for a given DSL. I'd like to keep it lean because that's what people will bundle.
I want to have a separate crate that adds serde and allows to serialize and deserialize the AST to/from json.
I think that this limitation prevents me from being able to do that.
sinkuu commentedon Dec 30, 2016
If this is allowed, adding
implss become a breaking-change, because any other crate could potentially have an conflicting impl. We need to bump minor version (or major version if>1.0.0) of a crate for every addition of trait impl. Moreover, as standard library is generally not allowed to make breaking-change, we can't implement existing std traits for existing std types anymore.if your concern is the additional dependencies, you can use features.
zbraniecki commentedon Jan 1, 2017
Sure, features are one option, but if I don't want to mess with the original package and keep it clean, I just end up with something like this:
https://github.com/zbraniecki/fluent-json-rs/blob/99a2b3e08306fe9b298769e0fbe3abf458e9c69e/src/lib.rs
which is a clone of https://github.com/projectfluent/fluent-rs/blob/70b5e8d387f3b836032b42c997c359263b21c8d0/src/syntax/ast.rs
but with From/Into. (to serialize FTL->AST->JSON and JSON->AST->FTL back).
I'm wondering if it would be possible to write code to automate the creation of a clone of a struct/enum from another crate. Then one could add Serialize/Deserialize on those local struct/enums.
Another option would be to mark structs/enums as extensible by other crates, which would allow the author to decide that he wants to let others impl features for them. That would work better in my case, because it would remove the step of converting from fluent::syntax::ast::* into fluent_json::ast::* back and forth.
oberien commentedon Mar 24, 2017
With specialization this is not an issue anymore. If some library implements
Foo for Vec<T>and I implementFoo for Vec<Bar>then with specialization both can co-exist and mine will be executed. Therefore I think that allowing implementations of traits for a type not defined in your crate but with a generic parameter from your trait could be allowed again. Do I miss another problem?nikomatsakis commentedon Mar 24, 2017
The bug is in the error message, which I agree is misleading. It's also true that it might be nice to rejigger the rules in this area, but that's a fairly complex undertaking.
nikomatsakis commentedon Mar 24, 2017
Here is a standalone test case for the same issue:
Generates:
I'm not sure of the ideal wording, but one idea would be to have it highlight the "foreign types" (in this example, there is only one, the
Vectype):I am not sure if that last note is all that useful either. Maybe. It seems very jargon heavy.
Anyway, the trick would be getting the highlight to exclude the
Bar. It may also be worth trying to comment on howBardoesn't count because it is "under"Vec.nayato commentedon Sep 12, 2017
Would it make sense to consider type parameters' boundaries to allow anchoring / scoping impls for non-local types? e.g.
Rollup merge of rust-lang#65318 - estebank:coherence, r=varkor
Rollup merge of rust-lang#65318 - estebank:coherence, r=varkor
Rollup merge of rust-lang#65318 - estebank:coherence, r=varkor
estebank commentedon Nov 15, 2019
The current output for this case is:
For the last comment:
For the original report:
@nikomatsakis is there anything else we should do here?
Arnavion commentedon Nov 18, 2019
I know what the issue is and what the fix is, but I don't understand what "define and implement a trait or new type instead" is trying to tell me.
"define and implement a trait or new type" should presumably be "define and implement a new trait, or implement the trait on a newtype". As it's written the suggestion doesn't make sense.
Even with that alternative wording, it implies either option is feasible, but realistically creating a brand new trait is unlikely to be what the user wants. It might be worth only mentioning the newtype option, or at least listing it first.
"note: define ..." should probably be "note: consider defining ...", because actually creating a newtype or new trait may not fit with the rest of the user's program. Just "define ... instead" implies the compiler's suggestion is a drop-in replacement.
So with all that, should it instead be "consider defining a newtype and implement the trait on it instead" ?
SimonSapin commentedon Apr 1, 2020
The original test case now compiles, I believe this was fixed with https://blog.rust-lang.org/2020/01/30/Rust-1.41.0.html#relaxed-restrictions-when-implementing-traits