Skip to content

Commit bbc6b26

Browse files
committed
Change __iterator_get_unchecked to work with TrustedRandomAccessNoCoerce
1 parent 69dd992 commit bbc6b26

File tree

8 files changed

+102
-68
lines changed

8 files changed

+102
-68
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ where
6363
#[doc(hidden)]
6464
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
6565
where
66-
Self: TrustedRandomAccess,
66+
Self: TrustedRandomAccessNoCoerce,
6767
{
6868
// SAFETY: the caller must uphold the contract for
6969
// `Iterator::__iterator_get_unchecked`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ where
7979
#[doc(hidden)]
8080
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
8181
where
82-
Self: TrustedRandomAccess,
82+
Self: TrustedRandomAccessNoCoerce,
8383
{
8484
// SAFETY: the caller must uphold the contract for
8585
// `Iterator::__iterator_get_unchecked`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ where
116116
#[doc(hidden)]
117117
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
118118
where
119-
Self: TrustedRandomAccess,
119+
Self: TrustedRandomAccessNoCoerce,
120120
{
121121
// SAFETY: the caller must uphold the contract for
122122
// `Iterator::__iterator_get_unchecked`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ where
132132
#[doc(hidden)]
133133
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
134134
where
135-
Self: TrustedRandomAccess,
135+
Self: TrustedRandomAccessNoCoerce,
136136
{
137137
match self.iter {
138138
// SAFETY: the caller must uphold the contract for

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ where
127127
#[doc(hidden)]
128128
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
129129
where
130-
Self: TrustedRandomAccess,
130+
Self: TrustedRandomAccessNoCoerce,
131131
{
132132
// SAFETY: the caller must uphold the contract for
133133
// `Iterator::__iterator_get_unchecked`.

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

Lines changed: 94 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ where
9191
#[doc(hidden)]
9292
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
9393
where
94-
Self: TrustedRandomAccess,
94+
Self: TrustedRandomAccessNoCoerce,
9595
{
9696
// SAFETY: `ZipImpl::__iterator_get_unchecked` has same safety
9797
// requirements as `Iterator::__iterator_get_unchecked`.
@@ -126,7 +126,66 @@ trait ZipImpl<A, B> {
126126
// This has the same safety requirements as `Iterator::__iterator_get_unchecked`
127127
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
128128
where
129-
Self: Iterator + TrustedRandomAccess;
129+
Self: Iterator + TrustedRandomAccessNoCoerce;
130+
}
131+
132+
// Work around limitations of specialization, requiring `default` impls to be repeated
133+
// in intermediary impls.
134+
macro_rules! zip_impl_general_defaults {
135+
() => {
136+
default fn new(a: A, b: B) -> Self {
137+
Zip {
138+
a,
139+
b,
140+
index: 0, // unused
141+
len: 0, // unused
142+
a_len: 0, // unused
143+
}
144+
}
145+
146+
#[inline]
147+
default fn next(&mut self) -> Option<(A::Item, B::Item)> {
148+
let x = self.a.next()?;
149+
let y = self.b.next()?;
150+
Some((x, y))
151+
}
152+
153+
#[inline]
154+
default fn nth(&mut self, n: usize) -> Option<Self::Item> {
155+
self.super_nth(n)
156+
}
157+
158+
#[inline]
159+
default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
160+
where
161+
A: DoubleEndedIterator + ExactSizeIterator,
162+
B: DoubleEndedIterator + ExactSizeIterator,
163+
{
164+
// The function body below only uses `self.a/b.len()` and `self.a/b.next_back()`
165+
// and doesn’t call `next_back` too often, so this implementation is safe in
166+
// the `TrustedRandomAccessNoCoerce` specialization
167+
168+
let a_sz = self.a.len();
169+
let b_sz = self.b.len();
170+
if a_sz != b_sz {
171+
// Adjust a, b to equal length
172+
if a_sz > b_sz {
173+
for _ in 0..a_sz - b_sz {
174+
self.a.next_back();
175+
}
176+
} else {
177+
for _ in 0..b_sz - a_sz {
178+
self.b.next_back();
179+
}
180+
}
181+
}
182+
match (self.a.next_back(), self.b.next_back()) {
183+
(Some(x), Some(y)) => Some((x, y)),
184+
(None, None) => None,
185+
_ => unreachable!(),
186+
}
187+
}
188+
};
130189
}
131190

132191
// General Zip impl
@@ -137,54 +196,8 @@ where
137196
B: Iterator,
138197
{
139198
type Item = (A::Item, B::Item);
140-
default fn new(a: A, b: B) -> Self {
141-
Zip {
142-
a,
143-
b,
144-
index: 0, // unused
145-
len: 0, // unused
146-
a_len: 0, // unused
147-
}
148-
}
149-
150-
#[inline]
151-
default fn next(&mut self) -> Option<(A::Item, B::Item)> {
152-
let x = self.a.next()?;
153-
let y = self.b.next()?;
154-
Some((x, y))
155-
}
156199

157-
#[inline]
158-
default fn nth(&mut self, n: usize) -> Option<Self::Item> {
159-
self.super_nth(n)
160-
}
161-
162-
#[inline]
163-
default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
164-
where
165-
A: DoubleEndedIterator + ExactSizeIterator,
166-
B: DoubleEndedIterator + ExactSizeIterator,
167-
{
168-
let a_sz = self.a.len();
169-
let b_sz = self.b.len();
170-
if a_sz != b_sz {
171-
// Adjust a, b to equal length
172-
if a_sz > b_sz {
173-
for _ in 0..a_sz - b_sz {
174-
self.a.next_back();
175-
}
176-
} else {
177-
for _ in 0..b_sz - a_sz {
178-
self.b.next_back();
179-
}
180-
}
181-
}
182-
match (self.a.next_back(), self.b.next_back()) {
183-
(Some(x), Some(y)) => Some((x, y)),
184-
(None, None) => None,
185-
_ => unreachable!(),
186-
}
187-
}
200+
zip_impl_general_defaults! {}
188201

189202
#[inline]
190203
default fn size_hint(&self) -> (usize, Option<usize>) {
@@ -205,12 +218,35 @@ where
205218

206219
default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
207220
where
208-
Self: TrustedRandomAccess,
221+
Self: TrustedRandomAccessNoCoerce,
209222
{
210223
unreachable!("Always specialized");
211224
}
212225
}
213226

227+
#[doc(hidden)]
228+
impl<A, B> ZipImpl<A, B> for Zip<A, B>
229+
where
230+
A: TrustedRandomAccessNoCoerce + Iterator,
231+
B: TrustedRandomAccessNoCoerce + Iterator,
232+
{
233+
zip_impl_general_defaults! {}
234+
235+
#[inline]
236+
default fn size_hint(&self) -> (usize, Option<usize>) {
237+
let size = cmp::min(self.a.size(), self.b.size());
238+
(size, Some(size))
239+
}
240+
241+
#[inline]
242+
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
243+
let idx = self.index + idx;
244+
// SAFETY: the caller must uphold the contract for
245+
// `Iterator::__iterator_get_unchecked`.
246+
unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
247+
}
248+
}
249+
214250
#[doc(hidden)]
215251
impl<A, B> ZipImpl<A, B> for Zip<A, B>
216252
where
@@ -330,14 +366,6 @@ where
330366
None
331367
}
332368
}
333-
334-
#[inline]
335-
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
336-
let idx = self.index + idx;
337-
// SAFETY: the caller must uphold the contract for
338-
// `Iterator::__iterator_get_unchecked`.
339-
unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
340-
}
341369
}
342370

343371
#[stable(feature = "rust1", since = "1.0.0")]
@@ -426,7 +454,9 @@ impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
426454
}
427455
}
428456

429-
impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B> for Zip<A, B> {
457+
impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
458+
for Zip<A, B>
459+
{
430460
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431461
// It's *not safe* to call fmt on the contained iterators, since once
432462
// we start iterating they're in strange, potentially unsafe, states.
@@ -448,6 +478,9 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B
448478
/// for bounds that come from the respective struct/enum definition itself, or bounds involving
449479
/// traits that themselves come with a guarantee similar to this one.
450480
///
481+
/// If `Self: ExactSizeIterator` then `self.len()` must always produce results consistent
482+
/// with `self.size()`.
483+
///
451484
/// If `Self: Iterator`, then `<Self as Iterator>::__iterator_get_unchecked(&mut self, idx)`
452485
/// must be safe to call provided the following conditions are met.
453486
///
@@ -463,6 +496,7 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B
463496
/// * `std::clone::Clone::clone`
464497
/// * `std::iter::Iterator::size_hint`
465498
/// * `std::iter::DoubleEndedIterator::next_back`
499+
/// * `std::iter::ExactSizeIterator::len`
466500
/// * `std::iter::Iterator::__iterator_get_unchecked`
467501
/// * `std::iter::TrustedRandomAccessNoCoerce::size`
468502
/// 5. If `T` is a subtype of `Self`, then `self` is allowed to be coerced
@@ -532,7 +566,7 @@ unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
532566
}
533567
}
534568

535-
unsafe impl<I: Iterator + TrustedRandomAccess> SpecTrustedRandomAccess for I {
569+
unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
536570
unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
537571
// SAFETY: the caller must uphold the contract for
538572
// `Iterator::__iterator_get_unchecked`.

library/core/src/iter/range.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ impl<A: Step> Iterator for ops::Range<A> {
676676
#[doc(hidden)]
677677
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
678678
where
679-
Self: TrustedRandomAccess,
679+
Self: TrustedRandomAccessNoCoerce,
680680
{
681681
// SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
682682
// that is in bounds.

library/core/src/iter/traits/iterator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use crate::cmp::{self, Ordering};
66
use crate::ops::{ControlFlow, Try};
77

8-
use super::super::TrustedRandomAccess;
8+
use super::super::TrustedRandomAccessNoCoerce;
99
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
1010
use super::super::{FlatMap, Flatten};
1111
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
@@ -3464,7 +3464,7 @@ pub trait Iterator {
34643464
#[unstable(feature = "trusted_random_access", issue = "none")]
34653465
unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item
34663466
where
3467-
Self: TrustedRandomAccess,
3467+
Self: TrustedRandomAccessNoCoerce,
34683468
{
34693469
unreachable!("Always specialized");
34703470
}

0 commit comments

Comments
 (0)