| > Whether the language was designed for it does not matter, as long as it works. And it works well. It matters fundamentally. "Works well" for research projects or limited AWS components is not equivalent to DO-178C Level A certification where mathematical proof is required. The verification community distinguishes between "we verified some properties of some code" and "the language guarantees these properties for all conforming code." > Few of the tools can verify unsafe code is free of UB With heavy annotation burden, for specific patterns. SPARK has no unsafe - the entire language is verifiable. That's the difference between "can be verified with effort" and "is verified by construction." > You don't need to prove anything about [traits/lifetimes]: they're purely a type level thing Trait resolution determines which code executes (monomorphization). Lifetimes affect drop order and program semantics. These aren't erased - they're compiled into the code being verified. SPARK's type system is verifiable; Rust's requires the verifier to trust the compiler's type checker. > The code that procedural macros generate is visible to these tools The macro logic is unverified Rust code executing at compile time. A bug in the macro generates incorrect code that may pass verification. SPARK has no equivalent escape hatch. > some of the tools do support interior mutability (with extra annotations I believe) Exactly - manual annotation burden. SPARK's verification is automatic for all conforming code. The percentage of manual proof effort is a critical metric in formal verification. > That is not a problem - in fact most of them prove precisely that: that code does not panic So they're doing what SPARK does automatically - proving absence of runtime errors. But SPARK guarantees this for the language; Rust tools must verify it per codebase. > you can follow what rustc does (and in fact it's easier for these tools, since they integrate with rustc) "Follow the compiler's behavior" is not formal semantics. Formal verification requires mathematical definitions independent of implementation. This is why SPARK has an ISO standard with formal semantics, not "watch what GNAT does." > Rust is very well amenable to formal verification [...] Perhaps even more amenable than Ada Then why doesn't it have DO-178C, EN 50128, or ISO 26262 certification toolchains after a decade? SPARK achieved this because verification was the design goal. Rust's design goals were different - and valid - but they weren't formal verifiability. > SPARK also does not support major parts of Ada Correct - by design. SPARK excludes features incompatible with efficient verification (unrestricted pointers, exceptions in contracts, controlled types). This is intentional subsetting for verification. Claiming Rust tools "support more of Rust" ignores that some Rust features are fundamentally unverifiable without massive annotation burden. The core issue: you're comparing research tools that can verify some properties of some Rust programs with significant manual effort, to a language designed so that conforming programs are automatically verifiable with mathematical guarantees. These are different categories of assurance. |
mrustc is existential proof that this statement is wrong. mrustc is a bootstrap compiler for Rust written in C++ that notably ignores lifetimes since it assumes that the code it is compiling (old rustc versions) will have correct lifetimes. And despite ignoring lifetimes, its output is bit-for-bit identical to what rustc produces, so clearly those lifetimes can't have been that important :P
(More seriously, lifetimes affect program correctness, but do not affect program semantics, let alone drop order. They are definitely erased as well. Not sure how you got this so wrong).
[0]: https://github.com/thepowersgang/mrustc