Skip to content

Commit e09c0af

Browse files
authored
axioms for has_resolved (#1857)
1 parent a372bae commit e09c0af

11 files changed

Lines changed: 546 additions & 51 deletions

File tree

source/rust_verify/src/fn_call_to_vir.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,9 +1606,9 @@ fn verus_item_to_vir<'tcx, 'a>(
16061606
format!("this builtin item should not appear in user code",),
16071607
);
16081608
}
1609-
VerusItem::Resolve | VerusItem::HasResolved => {
1609+
VerusItem::Resolve | VerusItem::HasResolved | VerusItem::HasResolvedUnsized => {
16101610
if !bctx.ctxt.cmd_line_args.new_mut_ref {
1611-
unsupported_err!(expr.span, "resolved/resolved without '-V new-mut-ref'", &args);
1611+
unsupported_err!(expr.span, "resolve/has_resolved without '-V new-mut-ref'", &args);
16121612
}
16131613
if matches!(verus_item, VerusItem::Resolve) {
16141614
record_compilable_operator(bctx, expr, CompilableOperator::Resolve);
@@ -1619,7 +1619,7 @@ fn verus_item_to_vir<'tcx, 'a>(
16191619
if matches!(verus_item, VerusItem::Resolve) {
16201620
return err_span(expr.span, "resolve must be in a 'proof' block");
16211621
} else {
1622-
return err_span(expr.span, "resolved must be in a 'proof' block");
1622+
return err_span(expr.span, "has_resolved must be in a 'proof' block");
16231623
}
16241624
}
16251625
let exp = expr_to_vir(bctx, &args[0], ExprModifier::REGULAR)?;

source/rust_verify/src/verifier.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,15 +1941,22 @@ impl Verifier {
19411941
reporter
19421942
.report_now(&note_bare(format!("verifying {bucket_name}{functions_msg}")).to_any());
19431943
}
1944-
let (pruned_krate, mono_abstract_datatypes, spec_fn_types, used_builtins, fndef_types) =
1945-
vir::prune::prune_krate_for_module_or_krate(
1946-
&krate,
1947-
&Arc::new(self.crate_name.clone().expect("crate_name")),
1948-
None,
1949-
Some(bucket_id.module().clone()),
1950-
bucket_id.function(),
1951-
true,
1952-
);
1944+
let (
1945+
pruned_krate,
1946+
mono_abstract_datatypes,
1947+
spec_fn_types,
1948+
used_builtins,
1949+
fndef_types,
1950+
resolved_typs,
1951+
) = vir::prune::prune_krate_for_module_or_krate(
1952+
&krate,
1953+
&Arc::new(self.crate_name.clone().expect("crate_name")),
1954+
None,
1955+
Some(bucket_id.module().clone()),
1956+
bucket_id.function(),
1957+
true,
1958+
true,
1959+
);
19531960
let mono_abstract_datatypes = mono_abstract_datatypes.unwrap();
19541961
let module = pruned_krate
19551962
.modules
@@ -1965,6 +1972,7 @@ impl Verifier {
19651972
spec_fn_types,
19661973
used_builtins,
19671974
fndef_types,
1975+
resolved_typs.unwrap(),
19681976
self.args.debugger,
19691977
)?;
19701978
if self.args.log_all || self.args.log_args.log_vir_poly {
@@ -2754,13 +2762,14 @@ impl Verifier {
27542762
vir_crates.push(vir_crate);
27552763
let unpruned_crate =
27562764
vir::ast_simplify::merge_krates(vir_crates).map_err(map_err_diagnostics)?;
2757-
let (vir_crate, _, _, _, _) = vir::prune::prune_krate_for_module_or_krate(
2765+
let (vir_crate, _, _, _, _, _) = vir::prune::prune_krate_for_module_or_krate(
27582766
&unpruned_crate,
27592767
&Arc::new(crate_name.clone()),
27602768
Some(&current_vir_crate),
27612769
None,
27622770
None,
27632771
false,
2772+
false,
27642773
);
27652774
let vir_crate =
27662775
vir::traits::merge_external_traits(vir_crate).map_err(map_err_diagnostics)?;

source/rust_verify/src/verus_items.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ pub(crate) enum VerusItem {
376376
External(ExternalItem),
377377
Resolve,
378378
HasResolved,
379+
HasResolvedUnsized,
379380
MutRefCurrent,
380381
MutRefFuture,
381382
ErasedGhostValue,
@@ -587,6 +588,7 @@ fn verus_items_map() -> Vec<(&'static str, VerusItem)> {
587588
("verus::verus_builtin::RqEn", VerusItem::External(ExternalItem::RqEn)),
588589
("verus::verus_builtin::resolve", VerusItem::Resolve),
589590
("verus::verus_builtin::has_resolved", VerusItem::HasResolved),
591+
("verus::verus_builtin::has_resolved_unsized", VerusItem::HasResolvedUnsized),
590592
("verus::verus_builtin::mut_ref_current", VerusItem::MutRefCurrent),
591593
("verus::verus_builtin::mut_ref_future", VerusItem::MutRefFuture),
592594
]

source/rust_verify_test/tests/mut_refs.rs

Lines changed: 124 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,8 @@ mod common;
44
use common::*;
55

66
test_verify_one_file_with_options! {
7-
#[test] test_basic ["new-mut-ref", "--no-lifetime"] => verus_code! {
8-
broadcast axiom fn resolved_defn<T>(a: &mut T)
9-
ensures
10-
#[trigger] has_resolved(a) ==> mut_ref_current(a) == mut_ref_future(a);
11-
7+
#[test] test_basic ["new-mut-ref"] => verus_code! {
128
fn test_no_update() {
13-
broadcast use resolved_defn;
14-
159
let mut u: u64 = 20;
1610
let u_ref: &mut u64 = &mut u;
1711

@@ -21,8 +15,6 @@ test_verify_one_file_with_options! {
2115
}
2216

2317
fn test_basic_update() {
24-
broadcast use resolved_defn;
25-
2618
let mut u: u64 = 20;
2719
let u_ref: &mut u64 = &mut u;
2820

@@ -36,8 +28,6 @@ test_verify_one_file_with_options! {
3628
struct Pair<A, B>(A, B);
3729

3830
fn test_field_update() {
39-
broadcast use resolved_defn;
40-
4131
let mut u: Pair<u64, u64> = Pair(20, 20);
4232
let u_ref: &mut Pair<u64, u64> = &mut u;
4333

@@ -50,8 +40,6 @@ test_verify_one_file_with_options! {
5040
}
5141

5242
fn test_field_update2() {
53-
broadcast use resolved_defn;
54-
5543
let mut u: Pair<u64, u64> = Pair(20, 20);
5644
let u_ref: &mut u64 = &mut u.0;
5745

@@ -64,21 +52,21 @@ test_verify_one_file_with_options! {
6452
}
6553

6654
fn test_mut_ref_in_pair() {
67-
broadcast use resolved_defn;
68-
6955
let mut u: u64 = 20;
7056
let u_ref: Pair<&mut u64, u64> = Pair(&mut u, 70);
7157

7258
*u_ref.0 = 30;
7359

74-
proof { resolve(u_ref.0) }
60+
proof {
61+
resolve(u_ref);
62+
assert(has_resolved(u_ref));
63+
assert(has_resolved(u_ref.0));
64+
}
7565

7666
assert(u == 30);
7767
}
7868

7969
fn test_reborrow() {
80-
broadcast use resolved_defn;
81-
8270
let mut u: u64 = 20;
8371
let u_ref: &mut u64 = &mut u;
8472

@@ -105,7 +93,7 @@ test_verify_one_file_with_options! {
10593
}
10694

10795
test_verify_one_file_with_options! {
108-
#[test] test_spec_functions_ok ["new-mut-ref", "--no-lifetime"] => verus_code! {
96+
#[test] test_spec_functions_ok ["new-mut-ref"] => verus_code! {
10997
spec fn test<T>(x: &mut T) -> T {
11098
mut_ref_current(x)
11199
}
@@ -123,17 +111,132 @@ test_verify_one_file_with_options! {
123111
}
124112

125113
test_verify_one_file_with_options! {
126-
#[test] test_mut_ref_future_proph ["new-mut-ref", "--no-lifetime"] => verus_code! {
114+
#[test] test_mut_ref_future_proph ["new-mut-ref"] => verus_code! {
127115
spec fn test<T>(x: &mut T) -> T {
128116
mut_ref_future(x)
129117
}
130118
} => Err(err) => assert_vir_error_msg(err, "cannot use prophecy-dependent function `mut_ref_future` in prophecy-independent context")
131119
}
132120

133121
test_verify_one_file_with_options! {
134-
#[test] test_resolved_proph ["new-mut-ref", "--no-lifetime"] => verus_code! {
122+
#[test] test_resolved_proph ["new-mut-ref"] => verus_code! {
135123
spec fn test<T>(x: &mut T) -> bool {
136124
has_resolved(x)
137125
}
138126
} => Err(err) => assert_vir_error_msg(err, "cannot use prophecy-dependent predicate `has_resolved` in prophecy-independent context")
139127
}
128+
129+
test_verify_one_file_with_options! {
130+
#[test] test_resolved_axioms ["new-mut-ref"] => verus_code! {
131+
use vstd::prelude::*;
132+
133+
proof fn test_pair<A, B>(pair: (A, B)) {
134+
assert(has_resolved(pair) ==> has_resolved(pair.0));
135+
assert(has_resolved(pair) ==> has_resolved(pair.1));
136+
}
137+
138+
proof fn test_option<A>(opt: Option<A>) {
139+
match opt {
140+
Some(o) => {
141+
assert(has_resolved(opt) ==> has_resolved(o));
142+
}
143+
None => { }
144+
}
145+
}
146+
147+
struct Pair<A, B> {
148+
x: A,
149+
y: B,
150+
}
151+
152+
proof fn test_pair_struct<A, B>(pair: Pair<A, B>) {
153+
assert(has_resolved(pair) ==> has_resolved(pair.x));
154+
assert(has_resolved(pair) ==> has_resolved(pair.y));
155+
}
156+
157+
proof fn test_box<A>(b: Box<A>) {
158+
assert(has_resolved(b) ==> has_resolved(*b));
159+
}
160+
161+
proof fn test_tracked<A>(t: Tracked<A>) {
162+
assert(has_resolved(t) ==> has_resolved(t@));
163+
}
164+
165+
proof fn test_ghost_fail<A>(t: Ghost<A>) {
166+
assert(has_resolved(t) ==> has_resolved(t@)); // FAILS
167+
}
168+
169+
proof fn test_ref_fail<A>(t: &A) {
170+
assert(has_resolved(t) ==> has_resolved(*t)); // FAILS
171+
}
172+
173+
proof fn test_rc_fail<A>(t: std::rc::Rc<A>) {
174+
assert(has_resolved(t) ==> has_resolved(*t)); // FAILS
175+
}
176+
177+
proof fn test_arc_fail<A>(t: std::sync::Arc<A>) {
178+
assert(has_resolved(t) ==> has_resolved(*t)); // FAILS
179+
}
180+
181+
proof fn test_mut_ref<A>(t: &mut A) {
182+
assert(has_resolved(t) ==> mut_ref_current(t) == mut_ref_future(t));
183+
}
184+
185+
proof fn test_mut_ref_fail<A>(t: &mut A) {
186+
assert(has_resolved(t) ==> has_resolved(mut_ref_current(t))); // FAILS
187+
}
188+
189+
proof fn test_mut_ref_fail2<A>(t: &mut A) {
190+
assert(has_resolved(t) ==> has_resolved(mut_ref_future(t))); // FAILS
191+
}
192+
} => Err(err) => assert_fails(err, 6)
193+
}
194+
195+
test_verify_one_file_with_options! {
196+
#[test] test_resolve_axioms_in_context ["new-mut-ref"] => verus_code! {
197+
use vstd::prelude::*;
198+
199+
fn box_with_mut_ref() {
200+
let mut x: u64 = 0;
201+
202+
let x_ref = &mut x;
203+
let x_ref_box = Box::new(x_ref);
204+
205+
**x_ref_box = 13;
206+
207+
proof { resolve(x_ref_box); }
208+
209+
assert(x == 13);
210+
}
211+
212+
fn shr_ref_with_mut_ref() {
213+
let mut x: u64 = 0;
214+
215+
let x_ref = &mut x;
216+
let x_ref_ref = &x_ref;
217+
218+
proof { resolve(x_ref_ref); }
219+
220+
assert(has_resolved(x_ref)); // FAILS
221+
222+
*x_ref = 20;
223+
proof { resolve(x_ref); }
224+
}
225+
226+
fn mut_ref_with_mut_ref() {
227+
let mut x: u64 = 0;
228+
229+
let mut x_ref = &mut x;
230+
let x_ref_ref = &mut x_ref;
231+
232+
**x_ref_ref = 20;
233+
234+
proof { resolve(x_ref_ref); }
235+
236+
assert(has_resolved(x_ref)); // FAILS
237+
238+
*x_ref = 30;
239+
proof { resolve(x_ref); }
240+
}
241+
} => Err(err) => assert_fails(err, 2)
242+
}

source/vir/src/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub struct Ctx {
8787
pub(crate) spec_fn_types: Vec<usize>,
8888
pub(crate) used_builtins: crate::prune::UsedBuiltins,
8989
pub(crate) fndef_types: Vec<Fun>,
90+
pub(crate) resolved_typs: Vec<crate::resolve_axioms::ResolvableType>,
9091
pub(crate) fndef_type_set: HashSet<Fun>,
9192
pub functions: Vec<Function>,
9293
pub func_map: HashMap<Fun, Function>,
@@ -713,6 +714,7 @@ impl Ctx {
713714
spec_fn_types: Vec<usize>,
714715
used_builtins: crate::prune::UsedBuiltins,
715716
fndef_types: Vec<Fun>,
717+
resolved_typs: Vec<crate::resolve_axioms::ResolvableType>,
716718
debug: bool,
717719
) -> Result<Self, VirErr> {
718720
let mut datatype_is_transparent: HashMap<Dt, bool> = HashMap::new();
@@ -758,6 +760,7 @@ impl Ctx {
758760
spec_fn_types,
759761
used_builtins,
760762
fndef_types,
763+
resolved_typs,
761764
fndef_type_set,
762765
functions,
763766
func_map,

source/vir/src/datatype_to_air.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,8 @@ pub fn datatypes_and_primitives_to_air(ctx: &Ctx, datatypes: &crate::ast::Dataty
828828
vec![]
829829
};
830830

831+
let resolve_axiom_commands = crate::resolve_axioms::resolve_axioms(ctx);
832+
831833
let mut commands: Vec<Command> = Vec::new();
832834
commands.extend(pointee_metadata_commands);
833835
commands.append(&mut opaque_sort_commands);
@@ -840,5 +842,6 @@ pub fn datatypes_and_primitives_to_air(ctx: &Ctx, datatypes: &crate::ast::Dataty
840842
commands.append(&mut axiom_commands);
841843
commands.extend(array_commands);
842844
commands.extend(strslice_commands);
845+
commands.extend(resolve_axiom_commands);
843846
Arc::new(commands)
844847
}

source/vir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub mod printer;
5858
pub mod prune;
5959
pub mod recursion;
6060
pub mod recursive_types;
61+
mod resolve_axioms;
6162
pub mod safe_api;
6263
mod scc;
6364
pub mod sst;

source/vir/src/poly.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ fn visit_exp(ctx: &Ctx, state: &mut State, exp: &Exp) -> Exp {
606606
}
607607
UnaryOpr::HasResolved(_t) => {
608608
let e = coerce_exp_to_poly(ctx, &e1);
609-
mk_exp_typ(&e1.typ, ExpX::UnaryOpr(op.clone(), e.clone()))
609+
mk_exp(ExpX::UnaryOpr(op.clone(), e.clone()))
610610
}
611611
}
612612
}
@@ -745,6 +745,17 @@ fn visit_trigs(ctx: &Ctx, state: &mut State, trigs: &Trigs) -> Trigs {
745745
Arc::new(trigs.iter().map(|e| visit_exps(ctx, state, e)).collect())
746746
}
747747

748+
pub(crate) fn visit_exp_native_for_pure_exp(ctx: &Ctx, exp: &Exp) -> Exp {
749+
let mut state = State {
750+
remaining_temps: HashSet::new(),
751+
types: ScopeMap::new(),
752+
temp_types: HashMap::new(),
753+
is_trait: false,
754+
in_exec_closure: false,
755+
};
756+
visit_exp_native(ctx, &mut state, exp)
757+
}
758+
748759
fn take_temp(state: &mut State, dest: &Dest) -> Option<VarIdent> {
749760
if dest.is_init {
750761
if let ExpX::VarLoc(x) = &dest.dest.x {

0 commit comments

Comments
 (0)