I would like to be able to call from within a method this compile-time assertion:
const _: () = assert!(Self::is_odd(123));
where is_odd is a const fn method.
This fails with can't use Self from outer item, which I can understand. Note that this is generated from within a macro so we do not have access to the qualified name of the struct and need to use Self.
My coworker found this workaround (inspired from the static_assert crate), which does work:
let _: [(); {
if !Self::is_odd(123) {
panic!("not odd!")
};
0
}] = [];
I don't really see why this is allowed and not the former. Is this a loophole that risks being closed one day, or can this be relied on?
impl Struct {
const fn is_odd(i: i32) -> bool { false }
// this will compile just fine, as associated consts are lazily evaluated
const _ASSERT: () = assert!(Self::is_odd(0));
// as will this, for the exact same reason
const _BOMB: () = panic!("boom");
}
// but not this
const _BOMB: () = panic!("boom");
But I still do not understand then why in the workaround Self::is_odd is evaluated a compile-time without problem (and rustc does actually require is_odd to be a const fn for this to work).
The initial array-size workaround actually does have an advantage over the nicer-looking const { assert!(Self::is_odd(123), "not odd"); }: it seems to be evaluated earlier in the compilation process.
In our case, the assert is used to give a nicer error message before calling a (potentially) non-existing method. With the const block, the assert error is never shown and only the rather cryptic error about the missing method is. But presumably because the array type is resolved first, the initial workaround shows the assert error.