#Workaround for conflicting trait impl

32 messages · Page 1 of 1 (latest)

south seal
#

In my library I have a structure similar to this:

use external_crate::External;

pub trait Marker { }

pub struct Wrap<T>(pub T);

impl<T: Marker> External for Wrap<T> { /* ... */ }
impl<T: External> External for Wrap<T> { /* ... */ }

This generates a conflicting trait impl on Wrap<_>. Ideally, I would have the error passed down to the library user if T impls both Marker and External. Are there any workarounds for this?

My goal is for my users to be able to mark some T as Marker and have an impl sort of generated for it for External, or be able to manually impl External themselves. External is tedious to implement manually, so I want to be able to write a kind of "default" impl which users can opt-in to

magic sand
#

but there isn't a way to declare that two traits are mutually exclusive

charred falcon
#

Given nightly, there technically is: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=16ee9632e009704513e7262f221a69c8

negative_impls allows us to write impl<T: LeftTrait + ?Sized> !RightTrait for T {}, and with_negative_coherence tells the coherence checker that it's allowed to use negative impls in its reasoning.

Note that I'm not too clear on whether this is intended. From what I heard, it's possible that, at least initially, negative impls will not be allowed to be blanket impls. Use this "feature" at your own risk.

south seal
south seal
# charred falcon Given nightly, there technically is: <https://play.rust-lang.org/?version=nightl...

I actually tried to mark my traits mutually exclusive with negative_impls. Like so:

pub trait Marker {}
impl<T: Marker> !External for Wrap<T> {}
impl<T: External> !Marker for Wrap<T> {}

impl<T: Marker> External for Wrap<T> { /* ... */ }
impl<T: External> External for Wrap<T> { /* ... */ }

This still triggers the conflicting impl tho. I figured that the compiler would be able to tell that the two impls cannot overlap. Is this intended or a limitation of the coherence checker?

Bear with me here since I'm just learning about what the coherence checker even is

magic sand
charred falcon
magic sand
charred falcon
#

I'm just learning about what the coherence checker even is
coherence is the property that there are no overlapping impls anywhere in a program, which means the coherence checker is the thing that says "you can't write this impl, it overlaps with that one"

#

(or in fact, the thing that emits most errors about trait impls)

charred falcon
south seal
south seal
magic sand
#

the part where it's only unimplemented for T: External is extremely dubious impl<T: External> !Marker for Wrap<T> {}

south seal
magic sand
#

simple, unconditional negative impls and coherence is probably fine, and is already used by the standard library

south seal
#

also for the sake of anyone who might come across this later, I played around with min_specialization in nightly, and it seemed like it would have worked for me if my External trait didn't have associated types which I need access to

charred falcon
#

Note that min_specialization, in its current state, is unsound: It can cause UB in safe code, if used incorrectly.

#

Which is the main reason it's not stable

south seal
#

I see. I thought that min_specialization was introduced specifically as a sound subset of specialization?

charred falcon
#

Yes, but then it turned out it's unsound anyway

#

There was an attempt

south seal
#

oh okay lol

#

so there should probably be a warning for that, right?

charred falcon
#

Isn't it under incomplete_features?

#

I thought it was

#

(that's a warn-by-default lint)

south seal
#

it doesn't seem to be

charred falcon
#

huh

south seal
#

anyway, thanks for the help both of you