Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assert negative trait bounds #8

Closed
ecstatic-morse opened this issue May 8, 2018 · 8 comments
Closed

Assert negative trait bounds #8

ecstatic-morse opened this issue May 8, 2018 · 8 comments

Comments

@ecstatic-morse
Copy link

To my knowledge, assert_impl! cannot assert that a given type T satisfies, for example, T: !Send.

@nvzqz
Copy link
Owner

nvzqz commented May 8, 2018

This has been mentioned previously at #2 (comment). I agree that this would be a useful feature; I just haven't thought of a way it can be implemented.

@ecstatic-morse
Copy link
Author

ecstatic-morse commented May 9, 2018

So, I wasn't aware that the negative trait bound syntax was only available on nightly (it appears in the docs for Rc<T>), but I did come up with a way to do assert_not_impl! with a few caveats:

struct Success;
#[derive(Clone)]
struct Negative;

trait NotClone {}
impl<T> NotClone for T where T: Clone {}

impl NotClone for Success {}  // No problem!
// impl NotClone for Failure {} // Causes a compiler error

This (ab)uses a blanket impl to cause types which implement a trait to fail to compile. Unfortunately, it only works for types which are defined in the crate in which the assertion is called. This seems like the normal use case for static_assertions. Also, it does not currently work for auto traits (Send and Sync). I filed issue 50551 to track this.

@nvzqz
Copy link
Owner

nvzqz commented May 9, 2018

Yeah, it seems that approach isn't viable as of yet. The compiler still has some bugs that it needs to iron out. Here are some other failed attempts.

@ecstatic-morse
Copy link
Author

Ah, it seems I'm not the first person to wander down this path. Do you consider the restriction that either the type or the trait must be defined in the same crate to be a deal breaker? It seems like that condition would be satisfied for most uses of assert_not_impl!.

@nvzqz
Copy link
Owner

nvzqz commented May 9, 2018

I'd like to see some issues—such as the compiler suggesting that [u8], an unsized type, can somehow implement Copy—ironed out before committing to this sort of implementation. Obvious assertions failing when they should be passing makes for very poor library design, in my opinion.

@ecstatic-morse
Copy link
Author

Oof, yeah, I agree. The error messages are pretty tough as well. Thanks for your time!

@HeroicKatora
Copy link
Contributor

HeroicKatora commented Aug 8, 2019

I've had a new idea for this: #17. Ambiguity in name resolution can also trigger a compilation error, thus we introduce two competing traits with the same method. One of the traits is always implemented while the other is only implemented when the trait bounds are met. When the type implements all the supplied trait the compiler can no longer resolve the method name to a single trait and compilation fails. When the trait bound is not met, the compilation succeeds. To ensure that no other trait may interfere with name resolution we include a single parameter that is of a local type, effectively sealing the method signature.

@nvzqz
Copy link
Owner

nvzqz commented Aug 11, 2019

This is resolved by #17, which was just merged.

@nvzqz nvzqz closed this as completed Aug 11, 2019
@nvzqz nvzqz added this to the Stable (v1.0.0) milestone Aug 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants