Specs for conversion to and from float types with as#2224
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a conservative (nondeterministic) verification model for Rust as casts involving floating-point types by desugaring casts into fresh nondeterministic values constrained by uninterpreted _ensures predicates in vstd::float.
Changes:
- Introduces
vstd::float::{src}_as_{dst}_ensuresuninterpreted spec predicates for int/float casts. - Lowers Rust
ascasts between ints/floats (and f32<->f64) intoUnaryOp::NondeterministicCast, then desugars inast_to_sstinto nondet temps +assumeof the relevant_ensurespredicate. - Updates VIR plumbing (pruning, triggers, printing, AIR conversion guards) and adds verification tests covering the new behavior.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| source/vstd/float.rs | Adds _as_..._ensures uninterpreted predicates for cast specs (currently f32/f64 targets and Rust primitive integer sources). |
| source/vir/src/ast.rs | Introduces CastType and UnaryOp::NondeterministicCast. |
| source/vir/src/ast_util.rs | Adds cast_type_to_type_string used to build _ensures function names. |
| source/vir/src/def.rs | Adds fn_cast_ensures to construct the vstd::float::{src}_as_{dst}_ensures Fun path. |
| source/vir/src/ast_to_sst.rs | Desugars NondeterministicCast into nondet temp + assume has_type + assume _ensures(...). |
| source/rust_verify/src/rust_to_vir_expr.rs | Lowers Rust as casts between ints/floats (and float width changes) into NondeterministicCast. |
| source/vir/src/prune.rs | Ensures the referenced _ensures functions are marked reachable. |
| source/vir/src/triggers_auto.rs | Updates auto-trigger term gathering for the new unary op. |
| source/vir/src/triggers.rs | Allows the new unary op in trigger validation logic. |
| source/vir/src/sst_util.rs | Adds string rendering for NondeterministicCast. |
| source/vir/src/sst_to_air.rs | Adds a defensive panic if NondeterministicCast reaches AIR lowering (should be desugared earlier). |
| source/vir/src/poly.rs | Adds a defensive panic if NondeterministicCast reaches poly phase. |
| source/vir/src/bitvector_to_air.rs | Adds a defensive panic if NondeterministicCast reaches bitvector lowering. |
| source/vir/src/interpreter.rs | Marks the new unary op as acceptable in interpreter’s unary-op whitelist. |
| source/vir/src/heuristics.rs | Treats the new unary op as a no-op for heuristic rewriting. |
| source/rust_verify_test/tests/float.rs | Adds tests asserting _ensures holds for casts and that repeated casts are nondeterministic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
There was a problem hiding this comment.
Right now, most nontrivial as-casts are implemented by writing an exec function in vstd and then emitting a call to that function in rust_to_vir. For example, casting an array pointer to a slice is implemented by a function cast_array_ptr_to_slice_ptr which is emitted here.
I'd prefer floating point casts be implemented this way, too. (Unless there's a compelling automation-related reason that requires special VIR logic). This doesn't require any VIR changes, and the specifications are easy to maintain and document.
I agree with this. Since we already have ways to represent nondeterminism in VIR, we don't have to add a new mechanism for nondeterminism to implement floating point casts. We can just do it with function calls, the same way that @tjhance mentioned for pointer casts. In addition, I would rather not declare a separate function for each cast ( Specifically, I would recommend starting with the following diff (some of which is taken verbatim from #2229 and some of which is a declaration of a new |
|
Thanks, @tjhance and @Chris-Hawblitzel! How does it look now? |
Chris-Hawblitzel
left a comment
There was a problem hiding this comment.
There's a lot of repeated code in rust_to_vir_expr.rs across the three cases (int->float, float->int, and float->float) that could be refactored so that the code is shared, but it may be easier for me to just do this myself after the merge rather than going through additional rounds of review. Everything else looks fine.
OK, done. |
Add a test case for f32 to f64 casting error handling.
eae8268
into
verus-lang:ieee-float-as-float
Written by Github Copilot + Claude Opus 4.6
By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.