Skip to content

Commit e80e689

Browse files
author
Kasim Te
committed
Address Copilot review feedback on PR model-checking#549
- Remove unused `loop_invariant` import in take.rs and zip.rs (#[cfg_attr(kani, kani::loop_invariant(...))] does not require it) - Rewrite `Zip::get_unchecked` `#[requires(...)]` to avoid `self.index + idx` overflow, using subtraction-based bounds - Clarify "vacuous loop invariant" comments in take.rs and zip.rs — note that `true` is intentional and only enables loop-contract mode - Reword "Loop invariant:" to "Safety argument:" in array_chunks.rs to avoid implying a verified invariant where there is none (bounded harness)
1 parent 6cca1ff commit e80e689

3 files changed

Lines changed: 18 additions & 11 deletions

File tree

library/core/src/iter/adapters/array_chunks.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,9 @@ where
232232
let inner_len = self.iter.size();
233233
let mut i = 0;
234234
// Use a while loop because (0..len).step_by(N) doesn't optimize well.
235-
// Loop invariant: __iterator_get_unchecked is read-only for
235+
// Safety argument: __iterator_get_unchecked is read-only for
236236
// TrustedRandomAccessNoCoerce iterators, so iter.size() is preserved.
237-
// Loop invariant: i tracks the consumed element count and stays within
237+
// Safety argument: i tracks the consumed element count and stays within
238238
// inner_len. Combined with the while condition (inner_len - i >= N),
239239
// this ensures i + local < inner_len = iter.size() for all accesses.
240240
while inner_len - i >= N {

library/core/src/iter/adapters/take.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use safety::loop_invariant;
2-
31
use crate::cmp;
42
use crate::iter::adapters::SourceIter;
53
use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, TrustedRandomAccess};
@@ -303,8 +301,10 @@ impl<I: Iterator + TrustedRandomAccess> SpecTake for Take<I> {
303301
{
304302
let mut acc = init;
305303
let end = self.n.min(self.iter.size());
306-
// Loop invariant: __iterator_get_unchecked is a read-only operation for
307-
// TrustedRandomAccess iterators, so iter.size() is preserved across iterations.
304+
// __iterator_get_unchecked is a read-only operation for TrustedRandomAccess
305+
// iterators, so iter.size() is preserved across iterations.
306+
// The Kani loop invariant below is intentionally vacuous (`true`) and
307+
// is used only to enable loop-contract mode.
308308
#[cfg_attr(kani, kani::loop_invariant(true))]
309309
for i in 0..end {
310310
// SAFETY: i < end <= self.iter.size() and we discard the iterator at the end

library/core/src/iter/adapters/zip.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use safety::{loop_invariant, requires};
1+
use safety::requires;
22

33
use crate::cmp;
44
use crate::fmt::{self, Debug};
@@ -271,7 +271,12 @@ where
271271
}
272272

273273
#[inline]
274-
#[requires(self.index + idx < self.a.size() && self.index + idx < self.b.size())]
274+
#[requires(
275+
self.index <= self.a.size()
276+
&& idx < self.a.size() - self.index
277+
&& self.index <= self.b.size()
278+
&& idx < self.b.size() - self.index
279+
)]
275280
#[cfg_attr(kani, kani::modifies(self))]
276281
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
277282
let idx = self.index + idx;
@@ -287,12 +292,14 @@ where
287292
{
288293
let mut accum = init;
289294
let len = ZipImpl::size_hint(&self).0;
290-
// Loop invariant: get_unchecked is a read-only operation for
291-
// TrustedRandomAccessNoCoerce iterators, so sizes are preserved.
292-
// Loop invariant enables loop contracts for unbounded verification.
295+
// For TrustedRandomAccessNoCoerce iterators, get_unchecked is a
296+
// read-only operation, so sizes are preserved.
293297
// Safety of get_unchecked(i) is established by the pre-loop state:
294298
// len = min(a.size(), b.size()) - index, and get_unchecked adds index
295299
// back, so the actual index is always < both sizes.
300+
// The Kani loop invariant below is intentionally vacuous (`true`) and
301+
// is used only to enable loop-contract mode, not to encode these
302+
// bounds or size properties directly.
296303
#[cfg_attr(kani, kani::loop_invariant(true))]
297304
for i in 0..len {
298305
// SAFETY: since Self: TrustedRandomAccessNoCoerce we can trust the size-hint to

0 commit comments

Comments
 (0)