-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy pathinline.rs
246 lines (207 loc) · 5.66 KB
/
inline.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#![feature(rustc_private)]
#[macro_use]
mod common;
use common::*;
test_verify_one_file! {
#[test] test1 verus_code! {
#[verifier(inline)]
spec fn fi(x: int, y: int) -> int {
x + 2 * y
}
spec fn f1(x: int, y: int) -> int {
x + 2 * y
}
#[verifier(inline)]
spec fn f2(x: int, y: int) -> int {
f1(x, y)
}
#[verifier(inline)]
spec fn f3(a: int, b: int) -> int {
f1(a, b)
}
#[verifier(inline)]
spec fn f4(a: int, b: int) -> int {
let za = a + 1;
let zb = b + 1;
f1(za - 1, zb - 1)
}
#[verifier(inline)]
spec fn fg<A, B>(a: A, b: B) -> (B, A) {
(b, a)
}
spec fn fx(x: int) -> bool;
#[verifier(inline)]
spec fn fy(x: int) -> bool {
fx(x)
}
spec fn fpx<A>(x: A) -> bool;
#[verifier(inline)]
spec fn fpy<A>(x: A) -> bool {
fpx(x)
}
proof fn test()
requires
forall|i: int| fy(i),
forall|i: u8| fpy(i),
{
assert(fi(33, 44) == 121);
assert(f1(33, 44) == 121);
assert(f2(33, 44) == 121);
assert(f3(33, 44) == 121);
assert({let za = 44; f4(33, za) == 121});
assert(fg(10u8, true) === (true, 10u8));
assert(fx(7));
assert(fy(6));
assert(fpx(7u8));
assert(fpy(6u8));
}
} => Ok(())
}
test_verify_one_file! {
#[test] test_private_fails verus_code! {
#[verifier(inline)]
pub closed spec fn f(x: int, y: int) -> int {
x + 2 * y
}
} => Err(err) => assert_vir_error_msg(err, "'inline' is only allowed for private or 'open spec' functions")
}
test_verify_one_file! {
#[test] test_nonspec_fails verus_code! {
#[verifier(inline)]
proof fn f() {
}
} => Err(err) => assert_vir_error_msg(err, "'inline' is only allowed for 'spec' functions")
}
test_verify_one_file! {
#[test] test_rec_fails1 verus_code! {
#[verifier(inline)]
spec fn f(n: nat) -> nat
decreases n
{
0
}
} => Err(err) => assert_vir_error_msg(err, "'inline' functions cannot be recursive")
}
test_verify_one_file! {
#[test] test_rec_fails2 verus_code! {
#[verifier(inline)]
spec fn f(n: nat) -> nat
{
if n == 0 {
0
} else {
f((n - 1) as nat)
}
}
} => Err(err) => assert_vir_error_msg(err, "recursive function must have a decreases clause")
}
test_verify_one_file! {
#[test] test_no_body_fails verus_code! {
#[verifier(inline)]
spec fn f(n: nat) -> nat;
} => Err(err) => assert_vir_error_msg(err, "'inline' functions must have a body")
}
test_verify_one_file! {
#[test] test_spec_fn verus_code! {
#[verifier(inline)]
spec fn f1(i: int, j: int) -> bool {
i <= j
}
#[verifier(inline)]
spec fn f2(i: int, j: int) -> bool {
let x = i;
let y = j;
x < y
}
#[verifier(opaque)]
spec fn f3(i: int, j: int) -> bool {
f1(j, i)
}
fn test_spec_fn(a: int, b: int) {
hide(f2);
assume(f2(a, b));
proof {
reveal(f2);
}
assert(f1(a, b));
proof {
reveal(f3);
}
assert(f3(b, a));
assert(f3(a, b)); // FAILS
}
} => Err(err) => assert_one_fails(err)
}
test_verify_one_file! {
#[test] test_ensures_type_inference verus_code! {
struct Foo {
pub b: bool,
}
#[verifier(inline)]
spec fn get_b(foo: Foo) -> bool {
foo.b
}
fn test1() -> (b: Foo)
ensures get_b(b)
{
Foo { b: true }
}
} => Ok(())
}
test_verify_one_file! {
#[test] inline_poly verus_code! {
use vstd::prelude::*;
#[verifier::inline]
spec fn all_contains<A>(s1: Set<A>) -> bool {
forall|a: A| s1.contains(a)
}
proof fn failing_proof(s: Set<int>) {
assert(all_contains(s)); // FAILS
}
} => Err(err) => assert_one_fails(err)
}
test_verify_one_file! {
#[test] inline_poly_assoc_type verus_code! {
// https://github.com/verus-lang/verus/issues/1303
use vstd::prelude::*;
pub type SpecBytes = Seq<u8>;
pub type Bytes<'a> = &'a [u8];
pub enum SpecMsg {
M0(SpecBytes),
}
pub enum Msg<'a> {
M0(Bytes<'a>),
}
impl View for Msg<'_> {
type V = SpecMsg;
open spec fn view(&self) -> Self::V {
match self {
Msg::M0(m) => SpecMsg::M0(m@),
}
}
}
} => Ok(())
}
test_verify_one_file! {
#[test] default_impl_issue1407 verus_code! {
trait Tr {
#[verifier::inline]
spec fn foo(&self) -> bool { true }
}
struct X { }
impl Tr for X {
spec fn foo(&self) -> bool { false }
}
#[verifier::inline]
spec fn foo_wrapper_inlined<T: Tr>(t: &T) -> bool {
t.foo()
}
proof fn test4() {
let x = X { };
assert(foo_wrapper_inlined(&x)); // FAILS
}
proof fn test5<T: Tr>(t: &T) {
assert(foo_wrapper_inlined(t)); // FAILS
}
} => Err(err) => assert_fails(err, 2)
}