Repository: rust
Issue: Errors from trait incompatability for cfg(test) vs. non-cfg(test) very confusing
Labels: C-enhancement,A-diagnostics,A-trait-system,T-compiler

If there's a set of interconnected crates, it can be useful to have a crate take a `[dev-dependency]` on something that depends on the crate.

Well, it seems useful. But it's very easy to get into a situation where you're using versions of structs or traits compiled with the "regular" crate and are trying to use them in the "tested" crate.

Here's an example:

Run

```
cargo new cratea
cargo new crateb
```

Then edit:

`cratea/Cargo.toml`:

```toml
[package]
name = "cratea"
version = "0.1.0"
authors = ["David Ross <daboross@daboross.net>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dev-dependencies.crateb]
path = "../crateb"
```

`crateb/Cargo.toml`:

```toml

[package]
name = "crateb"
version = "0.1.0"
authors = ["David Ross <daboross@daboross.net>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies.cratea]
path = "../cratea"
```

`cratea/src/lib.rs`:

```rust
pub struct Foo;
pub trait Bar {}
pub fn takes_foo(v: Foo) {}
pub fn takes_bar(v: impl Bar) {}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn foo_works() {
        takes_foo(crateb::gives_foo());
    }
    #[test]
    fn bar_works() {
        takes_bar(crateb::gives_bar());
    }
}
```

`crateb/lib.rs`:

```rust
use cratea::{Foo, Bar};

pub struct BarImpl;
impl Bar for BarImpl {}

pub fn gives_foo() -> Foo {
    Foo
}
pub fn gives_bar() -> BarImpl {
    BarImpl
}
```

Finally, run `cargo test` in `cratea`. It gives the wonderfully confusing error mesage:

```rust
error[E0308]: mismatched types
  --> src/lib.rs:12:19
   |
12 |         takes_foo(crateb::gives_foo());
   |                   ^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found struct `cratea::Foo`

error[E0277]: the trait bound `crateb::BarImpl: Bar` is not satisfied
  --> src/lib.rs:16:19
   |
4  | pub fn takes_bar(v: impl Bar) {}
   |                          --- required by this bound in `takes_bar`
...
16 |         takes_bar(crateb::gives_bar());
   |                   ^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `crateb::BarImpl`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `cratea`.

To learn more, run the command again with --verbose.
```

<p><details>

<summary>`rustc --version --verbose`</summary>

```
rustc 1.46.0-nightly (7750c3d46 2020-06-26)
binary: rustc
commit-hash: 7750c3d46bc19784adb1ee6e37a5ec7e4cd7e772
commit-date: 2020-06-26
host: x86_64-unknown-linux-gnu
release: 1.46.0-nightly
LLVM version: 10.0
```
</details></p>

I ran into the trait case, which I think is arguably more confusing, as it doesn't immediately suggest that there are duplicate things involved (it's just missing an impl!).

If I recall correctly, there are already some custom error messages for a similar situation where you're using a struct from two different versions of the same crate. It'd be super helpful if the same or a similar better error was adapted to apply to this situation as well.