Skip to content

Commit cf79f2c

Browse files
authored
Add basic support for Iter::collect (#2449)
1 parent 633baa8 commit cf79f2c

4 files changed

Lines changed: 80 additions & 18 deletions

File tree

source/rust_verify_test/tests/iterators.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@
33
mod common;
44
use common::*;
55

6+
test_verify_one_file! {
7+
#[test] collect_works verus_code! {
8+
use vstd::prelude::*;
9+
10+
fn test(u: &Vec<u32>)
11+
{
12+
let v: Vec<u32> = vec![1, 2, 3, 4];
13+
let w: Vec<u32> = v.into_iter().collect();
14+
assert(v@ == w@);
15+
let x: Vec<u32> = w.into_iter().rev().collect();
16+
assert(x@ == seq![4u32, 3, 2, 1]);
17+
18+
let y: Vec<u32> = vec![1, 2, 3, 4];
19+
let z: Vec<u32> = y.into_iter().rev().rev().collect();
20+
assert(z@ == y@);
21+
}
22+
} => Ok(())
23+
}
24+
625
test_verify_one_file! {
726
#[test] map_can_be_implemented verus_code! {
827
use vstd::prelude::*;

source/vstd/std_specs/core.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,6 @@ pub struct ExOption<V>(core::option::Option<V>);
150150
#[verifier::reject_recursive_types_in_ground_variants(E)]
151151
pub struct ExResult<T, E>(core::result::Result<T, E>);
152152

153-
pub open spec fn iter_into_iter_spec<I: Iterator>(i: I) -> I {
154-
i
155-
}
156-
157-
#[verifier::when_used_as_spec(iter_into_iter_spec)]
158-
pub assume_specification<I: Iterator>[ <I as IntoIterator>::into_iter ](i: I) -> (r: I)
159-
ensures
160-
r == i,
161-
;
162-
163153
// I don't really expect this to be particularly useful;
164154
// this is mostly here because I wanted an easy way to test
165155
// the combination of external_type_specification & external_body

source/vstd/std_specs/iter.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,10 @@ use super::super::seq::{
55

66
use verus as verus_;
77

8-
use core::iter::{Iterator, Rev};
8+
use core::iter::{FromIterator, Iterator, Rev};
99

1010
verus_! {
1111

12-
#[verifier::external_trait_specification]
13-
pub trait ExIntoIterator {
14-
type ExternalTraitSpecificationFor: core::iter::IntoIterator;
15-
}
16-
17-
1812
#[verifier::external_trait_specification]
1913
#[verifier::external_trait_extension(IteratorSpec via IteratorSpecImpl)]
2014
pub trait ExIterator {
@@ -91,6 +85,15 @@ pub trait ExIterator {
9185
r == into_rev_spec(self) && rev_post(self, r),
9286
;
9387

88+
fn collect<B>(self) -> (collection: B)
89+
where
90+
B: FromIterator<Self::Item>,
91+
Self: Sized,
92+
default_ensures
93+
self.will_return_none(),
94+
self.obeys_prophetic_iter_laws() && self.initial_value_relation(&self) ==>
95+
FromIteratorSpec::from_iter_ensures(self.remaining(), collection),
96+
;
9497
}
9598

9699
#[verifier::external_trait_specification]
@@ -136,6 +139,50 @@ pub trait ExDoubleEndedIterator : Iterator {
136139
spec fn peek_back(&self, index: int) -> Option<Self::Item>;
137140
}
138141

142+
/********************************************************************************
143+
* Definitions for `IntoIterator` and `FromIterator``
144+
********************************************************************************/
145+
#[verifier::external_trait_specification]
146+
pub trait ExIntoIterator {
147+
type ExternalTraitSpecificationFor: core::iter::IntoIterator;
148+
}
149+
150+
pub open spec fn iter_into_iter_spec<I: Iterator>(i: I) -> I {
151+
i
152+
}
153+
154+
#[verifier::when_used_as_spec(iter_into_iter_spec)]
155+
pub assume_specification<I: Iterator>[ <I as IntoIterator>::into_iter ](i: I) -> (r: I)
156+
ensures
157+
r == i,
158+
;
159+
160+
// Uninterpreted function representing the sequence of elements that will be
161+
// produced by the iterator obtained from an IntoIterator value.
162+
// This avoids requiring IteratorSpec bounds in from_iter's ensures clause.
163+
pub uninterp spec fn into_iter_remaining<A, T>(iter: T) -> Seq<A>;
164+
165+
// Connects into_iter_remaining to remaining() for types implementing Iterator + IteratorSpec.
166+
// This allows callers of from_iter to relate the result to the iterator's remaining elements.
167+
pub broadcast axiom fn axiom_from_iterator_ensures<A, I: Iterator<Item = A> + IteratorSpec>(iter: I)
168+
ensures
169+
#[trigger] into_iter_remaining::<A, I>(iter) == iter.remaining(),
170+
;
171+
172+
#[verifier::external_trait_specification]
173+
#[verifier::external_trait_extension(FromIteratorSpec via FromIteratorSpecImpl)]
174+
pub trait ExFromIterator<A>: Sized {
175+
type ExternalTraitSpecificationFor: FromIterator<A>;
176+
177+
spec fn from_iter_ensures(remaining: Seq<A>, s: Self) -> bool;
178+
179+
fn from_iter<T>(iter: T) -> (s: Self)
180+
where T: IntoIterator<Item = A>
181+
ensures
182+
Self::from_iter_ensures(into_iter_remaining(iter), s),
183+
;
184+
}
185+
139186
/********************************************************************************
140187
* Definitions for `rev()`
141188
********************************************************************************/

source/vstd/std_specs/vec.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::super::prelude::*;
2-
use super::iter::IteratorSpec;
2+
use super::iter::{FromIteratorSpecImpl, IteratorSpec};
33
use verus_builtin::*;
44

55
use super::super::slice::SliceIndexSpec;
@@ -462,6 +462,12 @@ pub assume_specification<'a, T, A: Allocator> [<&'a Vec<T, A> as core::iter::Int
462462
IteratorSpec::initial_value_relation(&iter, &iter),
463463
;
464464

465+
impl<T> FromIteratorSpecImpl<T> for Vec<T> {
466+
open spec fn from_iter_ensures(remaining: Seq<T>, s: Self) -> bool {
467+
remaining == s@
468+
}
469+
}
470+
465471
pub broadcast proof fn lemma_vec_obeys_eq_spec<T: PartialEq>()
466472
requires
467473
super::super::laws_eq::obeys_eq::<T>(),

0 commit comments

Comments
 (0)