static-assertions
static-assertions copied to clipboard
More Assertions
Discussion of other possible static assertions should occur here.
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.
@skade Just added assert_obj_safe, which is in release v0.2.1.
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
@skade Added assert_impl, which is in release v0.2.2 🎉
Would be cool to see an assertion that traits are not implemented: assert_not_impl.
There was some form of doing this that @kennytm recommend me. I don't exactly remember what it was.
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.
@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.
What about a macro to assert that two types are equal?
Could you add a macro that asserts that an enum variant exists?
@jendrikw I finally decided to close #9 with 1f470d2a0d6197214a748481265625e6e678ec62.
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
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 🤔
@nvzqz is there an issue for asserting Unpin and !Unpin? I know we talked about this at rustconf :)
@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. 😄
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.
@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 !...
That looks fine to me. Is it something that would be a good fit for this crate?
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.
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.
@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...
@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.
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.