Make Set and Map finite, add ISet and IMap. - #2486
Conversation
|
And as Anvil is added to verita, there will be more breaking changes in the future and I don't want to burden Verus developers (thank you @jaylorch!) with proofs on our side. You directly @ me or @marshtompsxd in the breaking PR, we will always be there to help. |
Thanks!!! |
There is a |
I somehow missed it. Thanks! |
|
I tried to fix broken proofs in Anvil and found this proof fails use vstd::prelude::*;
verus! {
proof fn repro(m: Map<int, int>, k1: int, k2: int)
requires
k2 != k1,
{
assert(m.insert(k1, 0)[k2] == m[k2]);
}
fn main() {}
}$ verus repro.rs
note: recommendation not met
--> repro.rs:18:12
|
18 | assert(m.insert(k1, 0)[k2] == m[k2]);
| ^^^^^^^^^^^^^^^^^^^
|
--> vstd/map.rs:87:12
|
= note: recommendation not met
error: assertion failed
--> repro.rs:18:12
|
18 | assert(m.insert(k1, 0)[k2] == m[k2]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assertion failed
note: recommendation not met
--> repro.rs:18:35
|
18 | assert(m.insert(k1, 0)[k2] == m[k2]);
| ^^^^^
|
--> vstd/map.rs:87:12
|
= note: recommendation not met
verification results:: 1 verified, 1 errors
error: aborting due to 1 previous errorPreviously this would pass verus, now without explicit |
|
Interesting observation, thanks! I looked into it more, and found this: It's always been the case that indexing into a map using a key that isn't in its domain produces a meaningless value. The way So it's not just a triggering issue. For finite maps, indexing into keys outside the domain gives arbitrary results, and those results might be changed by an In general, it's good practice to not index into maps outside their domain for any type of map. Even for |
|
As for documenting it, that's a good idea. Where would it have helped to have documentation? On |
|
The reason for this behavior is the different signatures of the broadcast lemmas |
|
The ultimate reason why the behavior differs is that the new I could weaken this to remove the |
|
Ah, never mind, the new axiom The issue is just that |
I agree enforcing domain check is better.
|
|
@Chris-Hawblitzel and I just talked, and decided to preserve the property of |
|
Great! A lot of fixing efforts are saved. Thank you @jaylorch. And I guess it may be helpful to this reproduction proof to tests in Verus to prevent such in the future? |
…yped-finite-verita
…gable Integrates the 17 upstream commits since the fork base (3039efc), incl. Rust 1.95.0 -> 1.96.0 (verus-lang#2528), Set/Map made finite + ISet/IMap (verus-lang#2486, vstd 1690 -> 1858 verified), per-query solver tuning moved into the verifier (verus-lang#2531), and the shared bucket AIR context refactor (verus-lang#2523). Conflict resolution: - source/rustc_mir_build/: take upstream wholesale (rustc 1.96 internals + verus patches); our only delta was the 1.95 workaround, superseded by 1.96. - air/ast_util.rs + vir/sst_to_air.rs: take upstream -- verus-lang#2531 relocated the bitvector/nonlinear per-query options out of the command stream (mk_bitvector_option / mk_option_command) and into Verifier::apply_per_query_smt_options. - verifier.rs apply_per_query_smt_options: extended upstream's Z3/Cvc5-only match (non-exhaustive over our 4-variant SmtSolver) to OxiZ (z3-protocol, same params) and Adsmt. Adsmt arms are {} by design, documented from investigation: adsmt auto-bit-blasts BV (bvand/or/xor/not -> SAT backend; arithmetic via OxiZ delegation) and exposes no z3-style sat./tactic. keys; its arith theory is linear (nonlinear -> unknown -> OxiZ delegation), and :finite-field-* is a GF(2) boolean-SAT sibling, not nonlinear int/real. Toolchain: installed the rustc-dev + llvm-tools components for 1.96.0 (rust-toolchain.toml requires them; they were missing). Builds clean: vstd 1858 verified, 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: 윤병익 <yeun0908@gmail.com>
Verus has added finite sets and maps, in verus-lang/verus#2486. This PR adapts to that change.
Verus has added finite sets and maps, in verus-lang/verus#2486. This PR adapts to that change.
This PR migrates anvil in response to upstream change verus-lang/verus#2486 which separate (in)finite map/set
Set<A>andMap<A>now represent finite sets and maps, respectively.ISet<A>andIMap<A>are the new names for the old-style possibly-infinite sets and maps.This new design is motivated because (1) it allows recursive types, such as having an
enum Twith aSet<T>field; and (2) finite sets are quite common in user code, and it's easy to go down a wild goose chase trying to get an ambient broadcast property to instantiate that turns out to be a missing.finite().The simplest porting path for existing code is to use the infinite versions, which work like the previous single Set and Map. Replace Set with ISet, Map with IMap,
set!withiset!, andmap!withimap!.To exploit the finite sets, use the Set and Map types. Where you might have specified a set domain with a predicate (boolean closure) before, now you might start with a finite constructor and transform it with map or filter.
Or, even better, use the recently added
set_build!macro to produce a finite set. To produce a finite map, construct the finite domain as aSetand use it as the first parameter to the newMap::new.This PR addresses issue #1512.
By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.