cargo-check succeeds but cargo-build fails – What?

I recently encountered an issue with cargo check vs. cargo build. The former did succeed on my codebase, but the latter did not.

“Wait, what?”, you may ask. “Isn't check supposed to be build, but without actually creating the binary?“, you may say. Yes, it is. But in fact check and build have some differences which caused the latter to fail while the check succeeded.

Here's why.

Reproducing the issue

The first thing I tried was to reduce the issue to a minimal working (or rather “breaking”) example. I was able to reduce my example to the following piece of code:

struct Check;
impl Check {
    const CHECK: () = assert!(1 == 2);
}

fn main() {
    let _ = Check::CHECK;
}

The above piece of code declares a struct named “Check” and implements a associated constant on that type. The associated constant is of type empty tuple(, which compiles to nothing). Its right hand side is an assert macro call which asserts that 1 is equal to 2.

Further down, the code example implements the main function where it assigns an anonymous variable to the value of the associated constant of the Check type.

This example is really simple, and obviously this should not compile. The associated constant should be evaluated at compiletime and make the compiler yell at me, because after years of research, scientists have found out that 1 is indeed not equal to 2.

The problem

Of course I reported the problem upstream – turns out it was known and my report was a duplicate (first report).

The problem here is that the associated constant gets evaluated only at monomorphization time. And cargo check does not do that step during checking of the codebase – although one might argue that it should, because users would expect it to catch such compilation errors.

The solution

The solution for this issue seems to be pending, as the bug in the rust compiler is not yet resolved. Ralf Jung suggested that we could fake monomorphization and ask the compiler to emit metadata during cargo check (if I understood the comment correctly). This way, the issue could potentially be found.

I did not test this though.

Takeaway

The takeaway for me here is that CI should never just cargo check the code. There must be at least one cargo build in your CI setup that builds all of the code.

Besides that I learned about the awesome stuff you can build with const assertions. But that's only slightly related here.