Skip to main content

vstd_extra/
panic.rs

1//! Runtime panic helper whose type (`-> !`) lets Verus discharge
2//! post-conditions by branch elimination at the call site.
3use vstd::prelude::*;
4use vstd::vpanic;
5
6verus! {
7
8/// Represents the intention that the code will panic at some point in the future.
9/// Consumed by [`panic_diverge`] to ensure that the top-level API spec must always
10/// intentionally document potential panics.
11pub uninterp spec fn may_panic() -> bool;
12
13/// Unconditionally diverges. Must be provided with a [`may_panic()] token to ensure that
14/// the panic is expected.
15#[verifier::external_body]
16pub fn panic_diverge() -> !
17    requires
18        may_panic(),
19{
20    vpanic!("")
21}
22
23/// Extension trait providing a panicking `unwrap` that models Rust's
24/// real `Option::unwrap` semantics.
25///
26/// Verus' `Option::unwrap` carries a `requires self is Some`; Rust's
27/// `unwrap` instead panics on `None`. `unwrap_or_panic` *diverges* on
28/// `None` (via [`panic_diverge`]) — a sound model of the real panic —
29/// and discharges `is_present()` (i.e. `self is Some` for `Option`) at
30/// the call site by branch elimination, so callers need not prove the
31/// value is populated.
32pub trait UnwrapOrPanic: Sized {
33    type Inner;
34
35    spec fn is_present(&self) -> bool;
36
37    spec fn payload(&self) -> Self::Inner;
38
39    fn unwrap_or_panic(self) -> (r: Self::Inner)
40        requires
41            !self.is_present() ==> may_panic(),
42        ensures
43            self.is_present(),
44            r == self.payload(),
45    ;
46}
47
48impl<T> UnwrapOrPanic for Option<T> {
49    type Inner = T;
50
51    open spec fn is_present(&self) -> bool {
52        self is Some
53    }
54
55    open spec fn payload(&self) -> T {
56        self->0
57    }
58
59    fn unwrap_or_panic(self) -> (r: T) {
60        match self {
61            Some(v) => v,
62            None => panic_diverge(),
63        }
64    }
65}
66
67} // verus!