Digging into the subject of the orphan rule, I ended up with a kind of implementation of a trait by a type both defined outside the implementing crate. But as a result, I now have another question about trait implementation. The following example works well:
orphan/ | c1/ | src/lib.rs | pub trait MyTrait<T> {
| | | fn my_task(&self);
| | | }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c2/ | src/lib.rs | pub struct MyStruct;
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c3/ | src/lib.rs | use c1::MyTrait; use c2::MyStruct;
| | | pub enum MyT {}
| | | impl MyTrait<MyT> for MyStruct {
| | | fn my_task(&self) { println!("This is c3 implementation"); }
| | | }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c4/ | src/lib.rs | use c1::MyTrait; use c2::MyStruct;
| | | pub enum MyT {}
| | | impl MyTrait<MyT> for MyStruct {
| | | fn my_task(&self) { println!("This is c4 implementation"); }
| | | }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c5/ | src/main.rs | mod _3 {
| | | use c1::*; use c2::*; use c3::*;
| | | pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
| | | }
| | | mod _4 {
| | | use c1::*; use c2::*; use c4::*;
| | | pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
| | | }
| | | fn main() { _3::f(); _4::f(); }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| Cargo.toml | [workspace]
| members = [ "c1", "c2", "c3", "c4", "c5", ]
with result:
cargo run --release
Compiling c5 v0.0.1 (XXX\orphan\c5)
Finished release [optimized] target(s) in 0.27s
Running `target\release\c5.exe`
This is c3 implementation
This is c4 implementation
But if I replace the main by:
main.rs | mod _3 {
| use c1::*; use c2::*; use c3::*;
| pub fn f() { MyTrait::my_task(&MyStruct); }
| }
| mod _4 {
| use c1::*; use c2::*; use c4::*;
| pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
| }
| fn main() { _3::f(); _4::f(); }
the following error is obtained:
--> c5\src\main.rs:3:18
|
3 | pub fn f() { MyTrait::my_task(&MyStruct); }
| ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the trait `MyTrait`
|
= note: multiple `impl`s satisfying `c2::MyStruct: c1::MyTrait<_>` found in the following crates: `c3`, `c4`:
- impl c1::MyTrait<c3::MyT> for c2::MyStruct;
- impl c1::MyTrait<c4::MyT> for c2::MyStruct;
Why such error, while "use c3::...;" and "use c4::...;" are applied within separated mods?
By the way, the following case works perfectly (unused_imports allowed only to avoid warnings):
main.rs | mod _3 {
| use c1::*; use c2::*; #[allow(unused_imports)] use c3::*;
| pub fn f() { MyTrait::my_task(&MyStruct); }
| }
| fn main() { _3::f(); }
with result:
cargo run --release
Compiling c5 v0.0.1 (XXX\orphan\c5)
Finished release [optimized] target(s) in 0.28s
Running `target\release\c5.exe`
This is c3 implementation
This behavior is thus a little bit strange : the compiler desagrees with the absence of turbofish only when both c3::MyT and c4::MyT are used, but that seems unlogic because they are used in separated mods.
ADD-ON: Detailed definition of the cargo files:
c1/Cargo.toml | [package]
| name = "c1"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
c2/Cargo.toml | [package]
| name = "c2"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
c3/Cargo.toml | [package]
| name = "c3"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
| c1 = { path = "../c1", version = "0.0.1" }
| c2 = { path = "../c2", version = "0.0.1" }
c4/Cargo.toml | [package]
| name = "c4"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
| c1 = { path = "../c1", version = "0.0.1" }
| c2 = { path = "../c2", version = "0.0.1" }
c5/Cargo.toml | [package]
| name = "c5"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
| c1 = { path = "../c1", version = "0.0.1" }
| c2 = { path = "../c2", version = "0.0.1" }
| c3 = { path = "../c3", version = "0.0.1" }
| c4 = { path = "../c4", version = "0.0.1" }