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

More Assertions #2

Open
nvzqz opened this issue Aug 13, 2017 · 22 comments
Open

More Assertions #2

nvzqz opened this issue Aug 13, 2017 · 22 comments

Comments

@nvzqz
Copy link
Owner

nvzqz commented Aug 13, 2017

Discussion of other possible static assertions should occur here.

@nvzqz nvzqz added this to the Stable (v1.0.0) milestone Aug 13, 2017
@skade
Copy link

skade commented Aug 13, 2017

Asserting Sync and Sendness: http://yakshav.es/asserting-static-properties/

Also, I'm still searching for a way to statically assert that a trait is object-safe.

@nvzqz
Copy link
Owner Author

nvzqz commented Aug 13, 2017

@skade Just added assert_obj_safe, which is in release v0.2.1.

@nvzqz
Copy link
Owner Author

nvzqz commented Aug 13, 2017

Here's a sample definition of a macro that would assert certain traits are implemented.

macro_rules! assert_impl {
    ($x:ty, $($xs:ty),+) => {
        $({
            fn _gen<T: ?Sized + $xs>() {}
            _gen::<$x>();
        })+
    };
    ($label:ident; $($xs:ty),+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_impl!($($xs),+); }
    };
}

However, when trying to use it, I get this error:

error: expected one of `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path, found `Sync`
   --> src/lib.rs:330:33
    |
330 |             fn _gen<T: ?Sized + $xs>() {}
    |                                -^^^ unexpected token
    |                                |
    |                                expected one of 8 possible tokens here
...
340 | assert_impl!(byte; u8, Sync);
    | ----------------------------- in this macro invocation

@nvzqz
Copy link
Owner Author

nvzqz commented Aug 13, 2017

@skade Added assert_impl, which is in release v0.2.2 🎉

@iliekturtles
Copy link

Would be cool to see an assertion that traits are not implemented: assert_not_impl.

@nvzqz
Copy link
Owner Author

nvzqz commented Dec 21, 2017

There was some form of doing this that @kennytm recommend me. I don't exactly remember what it was.

@matthiasbeyer
Copy link

I would love to have something like

assert_str_startswith!(str, "and")

Usecase is a CLI-builder-pattern subcrate I am trying to build for imag.

@nvzqz
Copy link
Owner Author

nvzqz commented May 10, 2018

@matthiasbeyer This would likely have to be implemented as a procedural macro. In that case, both parameters would have to be string literals. I'm curious if this could be done via const fn in combination with const_assert!. 🤔

@iliekturtles keep an eye on #8 in case such a macro becomes implemented.

@nvzqz nvzqz mentioned this issue Jun 4, 2018
8 tasks
@jendrikw
Copy link

jendrikw commented Jul 6, 2018

What about a macro to assert that two types are equal?

@robinkrahl
Copy link

Could you add a macro that asserts that an enum variant exists?

@nvzqz nvzqz pinned this issue Feb 23, 2019
@nvzqz nvzqz removed this from the Stable (v1.0.0) milestone Feb 23, 2019
@nvzqz
Copy link
Owner Author

nvzqz commented May 14, 2019

@jendrikw I finally decided to close #9 with 1f470d2.

It produces a rather nice error message:

error[E0308]: mismatched types
  --> tests/eq_ty.rs:12:5
   |
12 |     assert_eq_type!(byte; super::X, u8, usize, (super::X));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found usize

@DrSensor
Copy link

DrSensor commented Aug 19, 2019

Hi, I've struct and trait that require lifetime. My first though about using assert_impl_all is I need to specify the lifetime in precise manner:

assert_impl_all!(require;
	Transition<'t>,
	SemanticAnalyze<'t>,
	From<TokenPair<'t>>,
);

However, seems that's not supported. Rather I found traits need to be 'static lifetime:

assert_impl_all!(require;
	Transition,
	SemanticAnalyze<'static>,
	From<TokenPair<'static>>,
);

I think this should be anonymous '_ lifetime rather than 'static lifetime 🤔

This also give me an idea. What about macro for asserting lifetimes?


Ah yes, #![feature(underscore_const_names)] now has been stabilized 😁
https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
but in v0.3.4, it still require label despite using Rust-1.3.7 🤔

@LucioFranco
Copy link

@nvzqz is there an issue for asserting Unpin and !Unpin? I know we talked about this at rustconf :)

@nvzqz
Copy link
Owner Author

nvzqz commented Aug 30, 2019

@DrSensor the 1.0 beta is coming out soon. I'm dealing with life stuff which is why it hasn't come out yet. I tried getting around to it when 1.37 came out but I've had other priorities. Thanks for your patience!

@LucioFranco if you'd like to do the leg work to assert that the type of an expression implements given traits, please make a PR! To learn how to go about what we discussed, check out how assert_eq_size_val! and assert_{not,}_impl_{any,all}! are implemented. I'd be happy with doing it myself but this is a good opportunity to make a contribution I can mentor you on. 😄

@dtolnay
Copy link

dtolnay commented Feb 15, 2020

I am interested for a static assertion that some trait bound currently in scope is statically impossible.

Example:

#![feature(trivial_bounds)]

macro_rules! void {
    ($($tt:tt)*) => {
        unreachable!() // FIXME
    };
}

trait Trait {
    fn f() where Self: Sized;
}

impl Trait for str {
    fn f() where str: Sized {
        void!(str: Sized); // evaluate to !
    }
}

This assertion should require that both str: Sized is currently in scope (e.g. in the example let _s: str; does compile, where ordinarily it would not) and str: Sized is statically unsatisfiable.

@Nadrieril
Copy link
Contributor

Nadrieril commented Feb 17, 2020

@dtolnay: here is a sad version of what you ask:

macro_rules! void {
    ($ty:ty: $tr:path) => {{
        struct True;
        struct False;
        trait DoesImpl<M> {
            fn marker() {}
        }
        impl<T: ?Sized> DoesImpl<False> for T {}
        impl<T: ?Sized + $tr> DoesImpl<True> for T {}

        const _: () = {
            // Fails if `$ty: $tr` is in scope globally, because then it can't infer `M`
            let _ = <$ty as DoesImpl<_>>::marker;
        };
        // Fails if `$ty: $tr` is not in scope locally
        let _ = <$ty as DoesImpl<True>>::marker;

        unreachable!()
    }};
}

It will only typecheck in the case where the type does not implement the trait, but the bound $ty: $tr is in scope anyways.
I find this solution disappointing however: I'd love to be able to exploit the contradiction str: Sized + !Sized to construct a term of type !...

@dtolnay
Copy link

dtolnay commented Feb 25, 2020

That looks fine to me. Is it something that would be a good fit for this crate?

@sunshowers
Copy link

It would be fantastic to have static assertions added for lifetime parameter covariance/contravariance/invariance, since changing it in a public API can be a semver breakage.

@Kixunil
Copy link

Kixunil commented Jan 29, 2021

Is less than/greater than possible? More specifically, I'd be interested in $len <= u8::max_value(). Ideally for u16 and larger too (so exhaustive 256 trait impls should not be used) but limiting it to u8 is already useful. Bonus points if it works in Rust 1.41.1.

@konsumlamm
Copy link

@Kixunil isn't that already possible with const_assert!(len <= u8::MAX) (as long as len is const)? Apart from that, I'm not sure how something is ever going to be bigger than the maximum value of that type...

@Kixunil
Copy link

Kixunil commented Aug 19, 2021

@konsumlamm frankly, I don't remember what I wanted to use it for but I believe $len in a macro was not of type u8.

@HTGAzureX1212
Copy link

Hi, would an extension for lifetimes in the assertions be useful? I ran across an issue with traits that require lifetime parameters and have to manually write the assertion based on the expansion that the assert_* macros do.

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