Mutually exclusive trait impl

There is an issue #51774 for this. What I would like to understand is if this is something deeply rooted into the compiler, or if the compiler could be made to understand that the types can never overlap.

trait Test {
    type MemberOf;
}

struct A;
struct B;

trait Get {
    fn get(&self) -> &str;
}
/* impl<T: Test<MemberOf=A>> Get for T {
    fn get(&self) -> &str {
       "A"
    }
} */
impl<T: Test<MemberOf=B>> Get for T {
    fn get(&self) -> &str {
       "B"
    }
}

struct C;
impl Test for C {
    type MemberOf = A;
}

fn main() {
    println!("{}", C.get());
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0599]: the method `get` exists for struct `C`, but its trait bounds were not satisfied
  --> src/main.rs:28:22
   |
22 | struct C;
   | --------
   | |
   | method `get` not found for this struct
   | doesn't satisfy `<C as Test>::MemberOf = B`
   | doesn't satisfy `C: Get`
...
28 |     println!("{}", C.get());
   |                      ^^^ method cannot be called on `C` due to unsatisfied trait bounds
   |
note: trait bound `<C as Test>::MemberOf = B` was not satisfied
  --> src/main.rs:16:14
   |
16 | impl<T: Test<MemberOf=B>> Get for T {
   |              ^^^^^^^^^^   ---     -
   |              |
   |              unsatisfied trait bound introduced here

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` due to previous error

This is actually a slightly different issue, Can't write non-overlapping blanket impls that involve associated type bindings · Issue #20400 · rust-lang/rust · GitHub. #51774 is about explicit negative impls, but in this case, the two blanket impls could be known to be disjoint because they are bound on the use of disjoint associated types.

RFC#1672 was proposed to state intent to eventually accept these impls as non-overlapping, but it's been deferred waiting on the new Chalk trait resolution engine. Pretty much, this is waiting on Chalk such that we can have a proper model of what negative reasoning we allow the trait engine to rely on.

This specific case could be whitelisted in the current coherence checker, but adhoc extensions to a soundness-critical component like trait coherence/resolution carries a significant risk without a principled system like Chalk, especially when Chalk is coming down the pipeline[1].


  1. eventually, hopefully; ask #wg-traits on Zulip for up to date information ↩︎

5 Likes

Wasn't Chalk abandoned recently?

From what I understand Chalk is no-more, but that's actually a good thing: some less ambitious but more deliverable solution is supposed to materialize soon.

Not sure what would be cut out from it, though.

Thank you for your replies. Following the rabbit hole, I found that this can be achieved in stable Rust. It’s not pretty, though.

Ah, I overlooked that part of that announcement. Still, I'd say that the new inline trait solver is the spiritual successor to chalk w.r.t. things like this.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.