Skip to content

Commit b02cf68

Browse files
authored
bugfix: unhandled shadow case in get_manual_triggers (#2463)
1 parent 5074137 commit b02cf68

3 files changed

Lines changed: 298 additions & 180 deletions

File tree

source/rust_verify_test/tests/triggers.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,3 +549,101 @@ test_verify_one_file! {
549549
}
550550
} => Ok(())
551551
}
552+
553+
test_verify_one_file! {
554+
#[test] issue2342 verus_code! {
555+
use vstd::prelude::*;
556+
557+
#[verifier::inline]
558+
spec fn unwrap_or(a: Option<int>, b: int) -> int {
559+
match a {
560+
Some(x) => x,
561+
None => b,
562+
}
563+
}
564+
565+
spec fn f(opt: Option<int>, opt2: Option<int>) -> (spec_fn(int) -> bool) {
566+
|s: int| {
567+
match opt {
568+
Some(x) => {
569+
unwrap_or(opt2, 1) == x
570+
},
571+
None => { false }
572+
}
573+
}
574+
}
575+
576+
fn test() {
577+
assert(f(None, None)(0)); // FAILS
578+
}
579+
580+
fn test2() {
581+
assert(f(Some(1), None)(0));
582+
}
583+
} => Err(err) => assert_fails(err, 1)
584+
}
585+
586+
test_verify_one_file! {
587+
#[test] issue2342_2 verus_code! {
588+
use vstd::prelude::*;
589+
590+
#[verifier::inline]
591+
spec fn unwrap_or(a: Option<int>, b: int) -> int {
592+
match a {
593+
Some(x) => x,
594+
None => b,
595+
}
596+
}
597+
598+
spec fn f_quant(opt: Option<int>, opt2: Option<int>) -> bool {
599+
forall |s: int| {
600+
match opt {
601+
Some(x) => {
602+
unwrap_or(opt2, s) == x
603+
},
604+
None => { false }
605+
}
606+
}
607+
}
608+
609+
fn test3() {
610+
assert(f_quant(Some(2), Some(2)));
611+
}
612+
} => Err(err) => assert_vir_error_msg(err, "Could not automatically infer triggers for this quantifier")
613+
}
614+
615+
test_verify_one_file! {
616+
#[test] issue2123 verus_code! {
617+
use vstd::prelude::*;
618+
619+
pub enum A {
620+
Foo { xyz: Result<(), ()> },
621+
}
622+
623+
pub open spec fn foo(a: A) -> Set<nat> {
624+
Set::new(|x: nat| {
625+
match a {
626+
A::Foo { xyz, .. } => {
627+
let _ = xyz.ok();
628+
true
629+
},
630+
}
631+
})
632+
}
633+
} => Ok(())
634+
}
635+
636+
test_verify_one_file! {
637+
#[test] trigger_with_mixed_outer_quantifier_inner_closure verus_code! {
638+
spec fn foo(y: int, z: int) -> bool { y == z }
639+
640+
spec fn test(x: int) -> bool {
641+
forall |y: int| (|z: int| #[trigger] foo(y, z))(x)
642+
}
643+
} => Err(err) => {
644+
assert!(err.warnings.len() == 1);
645+
assert!(err.warnings[0].message.contains("#[trigger] on a spec_fn closure is deprecated"));
646+
assert!(err.errors.len() == 1);
647+
assert!(err.errors[0].message.contains("Could not automatically infer triggers for this quantifier"));
648+
}
649+
}

source/vir/src/sst_visitor.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,24 @@ pub(crate) trait Scoper {
2626
pub(crate) struct NoScoper;
2727
impl Scoper for NoScoper {}
2828

29-
pub type VisitorScopeMap = ScopeMap<VarIdent, bool>;
29+
pub enum BndKind {
30+
Let,
31+
Quant,
32+
Lambda,
33+
Choose,
34+
/// Used by a pass in triggers.rs to distinguish trigger variables of interest
35+
/// that are bound outside the walked expression.
36+
OuterTrigger,
37+
}
38+
39+
pub(crate) struct ScopeEntry {
40+
/// Is this a Quant, Choose, or Let?
41+
pub bnd_kind: BndKind,
42+
}
43+
44+
pub type VisitorScopeMap = ScopeMap<VarIdent, ScopeEntry>;
3045

31-
impl Scoper for ScopeMap<VarIdent, bool> {
46+
impl Scoper for ScopeMap<VarIdent, ScopeEntry> {
3247
fn push_scope(&mut self) {
3348
self.push_scope(true);
3449
}
@@ -38,17 +53,20 @@ impl Scoper for ScopeMap<VarIdent, bool> {
3853
}
3954

4055
fn insert_binding_typ(&mut self, binder: &VarBinder<Typ>, bnd_source: &Bnd) {
41-
let is_triggered = match bnd_source.x {
42-
BndX::Quant(..) | BndX::Choose(..) => true,
43-
BndX::Lambda(..) => false,
56+
let bnd_kind = match bnd_source.x {
57+
BndX::Quant(..) => BndKind::Quant,
58+
BndX::Choose(..) => BndKind::Choose,
59+
BndX::Lambda(..) => BndKind::Lambda,
4460
BndX::Let(..) => unreachable!(),
4561
};
46-
let _ = self.insert(binder.name.clone(), is_triggered);
62+
let entry = ScopeEntry { bnd_kind: bnd_kind };
63+
let _ = self.insert(binder.name.clone(), entry);
4764
}
4865

4966
fn insert_binding_exp(&mut self, binder: &VarBinder<Exp>, bnd_source: &Bnd) {
5067
assert!(matches!(bnd_source.x, BndX::Let(..)));
51-
let _ = self.insert(binder.name.clone(), true);
68+
let entry = ScopeEntry { bnd_kind: BndKind::Let };
69+
let _ = self.insert(binder.name.clone(), entry);
5270
}
5371
}
5472

0 commit comments

Comments
 (0)