From: Mara Bos Date: Sun, 22 Nov 2020 22:01:03 +0000 (+0100) Subject: Rollup merge of #79293 - Havvy:test-eval-order-compound-assign, r=Mark-Simulacrum X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=138845d43c31a1d5a9494ac3f996d6607f415cb5;hp=b6f9705804dd590ef9fa2842bae59ec7d9130f10;p=rust.git Rollup merge of #79293 - Havvy:test-eval-order-compound-assign, r=Mark-Simulacrum Add test for eval order for a+=b Yes, the order of evaluation *does* change depending on the types of the operands. Cursed, I know. I've elected to place this test into `expr/compound-assignment` creating both the `expr` directory and the `compound-assignment` directory. I plan in a future PR to also move the `if` directory and the loose `if` tests into `expr/if` and other similar cleanups of the `test/ui` directory. Future work: Test more than just `+=`, but all operators. I don't know if using a macro to generate these tests cases would be okay or not, but it'd be boilerplatey without it. I'm also confident you cannot change the evaluation order of one operator without changing all of them. Future work: Additionally, test more than just `i32 += i32` for the primitive version. I don't actually know the full set of primitive implementations, but I imagine there's enough to cause a combinatorial explosion with the previous future work item. Somewhere on the order of one to two hundred individual functions. --- diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 4bbc180b226..2a5ad5e6c98 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1152,7 +1152,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { /// ```rust /// #![feature(box_syntax)] /// fn main() { - /// let a = (box [1,2,3]).len(); + /// let a = (box [1, 2, 3]).len(); /// } /// ``` /// diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1d0d6980b7a..fa82dce0ae2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1719,7 +1719,7 @@ /// /// impl MyIterator for T where T: Iterator { } /// - /// let x = vec![1,2,3]; + /// let x = vec![1, 2, 3]; /// let _ = x.iter().is_sorted(); /// ``` /// diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index 6bea2381862..79a74e38743 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -3,6 +3,7 @@ //! - ui/or-patterns //! - ui/consts/const_in_pattern //! - ui/rfc-2008-non-exhaustive +//! - ui/half-open-range-patterns //! - probably many others //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific //! reason not to, for example if they depend on a particular feature like or_patterns. diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 0dfacd78908..b5b34c7338d 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -510,7 +510,7 @@ fn report_unterminated_raw_string( FatalError.raise() } - /// Note: It was decided to not add a test case, because it would be to big. + /// Note: It was decided to not add a test case, because it would be too big. /// fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! { self.fatal_span_( diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 6641ad33f92..a9e41687590 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1037,7 +1037,7 @@ pub fn range_mut(&mut self, range: R) -> RangeMut<'_, K, V> /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); /// /// // count the number of occurrences of letters in the vec - /// for x in vec!["a","b","a","c","a","b"] { + /// for x in vec!["a", "b", "a", "c", "a", "b"] { /// *count.entry(x).or_insert(0) += 1; /// } /// diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index f15959a1665..8c7913b533b 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -6,13 +6,14 @@ use crate::rc::Rc; use crate::string::{String, ToString}; use crate::vec::Vec; +use std::cmp::Ordering; use std::convert::TryFrom; use std::iter::{self, FromIterator}; use std::mem; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; mod ord_chaos; use ord_chaos::{Cyclic3, Governed, Governor}; @@ -1094,7 +1095,7 @@ fn drop_panic_leak() { struct D; impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + if DROPS.fetch_add(1, SeqCst) == 1 { panic!("panic in `drop`"); } } @@ -1105,14 +1106,14 @@ fn drop(&mut self) { catch_unwind(move || { drop(map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, Ordering::SeqCst); + PREDS.fetch_add(1usize << i, SeqCst); true })) }) .unwrap_err(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 3); } #[test] @@ -1123,7 +1124,7 @@ fn pred_panic_leak() { struct D; impl Drop for D { fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); + DROPS.fetch_add(1, SeqCst); } } @@ -1132,7 +1133,7 @@ fn drop(&mut self) { catch_unwind(AssertUnwindSafe(|| { drop(map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, Ordering::SeqCst); + PREDS.fetch_add(1usize << i, SeqCst); match i { 0 => true, _ => panic!(), @@ -1141,8 +1142,8 @@ fn drop(&mut self) { })) .unwrap_err(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 1); assert_eq!(map.len(), 2); assert_eq!(map.first_entry().unwrap().key(), &4); assert_eq!(map.last_entry().unwrap().key(), &8); @@ -1158,7 +1159,7 @@ fn pred_panic_reuse() { struct D; impl Drop for D { fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); + DROPS.fetch_add(1, SeqCst); } } @@ -1167,7 +1168,7 @@ fn drop(&mut self) { { let mut it = map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, Ordering::SeqCst); + PREDS.fetch_add(1usize << i, SeqCst); match i { 0 => true, _ => panic!(), @@ -1180,8 +1181,8 @@ fn drop(&mut self) { assert!(matches!(result, Ok(None))); } - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 1); assert_eq!(map.len(), 2); assert_eq!(map.first_entry().unwrap().key(), &4); assert_eq!(map.last_entry().unwrap().key(), &8); @@ -1315,8 +1316,6 @@ fn test_zst() { // undefined. #[test] fn test_bad_zst() { - use std::cmp::Ordering; - #[derive(Clone, Copy, Debug)] struct Bad; @@ -1763,7 +1762,7 @@ fn test_append_drop_leak() { impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 0 { + if DROPS.fetch_add(1, SeqCst) == 0 { panic!("panic in `drop`"); } } @@ -1779,7 +1778,7 @@ fn drop(&mut self) { catch_unwind(move || left.append(&mut right)).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), 4); // Rust issue #47949 ate one little piggy + assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy } #[test] @@ -1894,7 +1893,7 @@ fn test_into_iter_drop_leak_height_0() { impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 3 { + if DROPS.fetch_add(1, SeqCst) == 3 { panic!("panic in `drop`"); } } @@ -1909,7 +1908,7 @@ fn drop(&mut self) { catch_unwind(move || drop(map.into_iter())).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), 5); + assert_eq!(DROPS.load(SeqCst), 5); } #[test] @@ -1921,18 +1920,18 @@ fn test_into_iter_drop_leak_height_1() { struct D; impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) { + if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) { panic!("panic in `drop`"); } } } for panic_point in vec![0, 1, size - 2, size - 1] { - DROPS.store(0, Ordering::SeqCst); - PANIC_POINT.store(panic_point, Ordering::SeqCst); + DROPS.store(0, SeqCst); + PANIC_POINT.store(panic_point, SeqCst); let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect(); catch_unwind(move || drop(map.into_iter())).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), size); + assert_eq!(DROPS.load(SeqCst), size); } } diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 701d5ec73e2..93de2d829ac 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -50,7 +50,7 @@ pub fn search_node( { match search_linear(&node, key) { (idx, true) => Found(unsafe { Handle::new_kv(node, idx) }), - (idx, false) => SearchResult::GoDown(unsafe { Handle::new_edge(node, idx) }), + (idx, false) => GoDown(unsafe { Handle::new_edge(node, idx) }), } } diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index ef40a048a38..4d05bc4ebfa 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -1,9 +1,10 @@ use super::super::DeterministicRng; use super::*; use crate::vec::Vec; +use std::cmp::Ordering; use std::iter::FromIterator; use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; #[test] fn test_clone_eq() { @@ -355,7 +356,7 @@ fn test_drain_filter_drop_panic_leak() { struct D(i32); impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + if DROPS.fetch_add(1, SeqCst) == 1 { panic!("panic in `drop`"); } } @@ -368,14 +369,14 @@ fn drop(&mut self) { catch_unwind(move || { drop(set.drain_filter(|d| { - PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst); + PREDS.fetch_add(1u32 << d.0, SeqCst); true })) }) .ok(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 3); } #[test] @@ -387,7 +388,7 @@ fn test_drain_filter_pred_panic_leak() { struct D(i32); impl Drop for D { fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); + DROPS.fetch_add(1, SeqCst); } } @@ -398,7 +399,7 @@ fn drop(&mut self) { catch_unwind(AssertUnwindSafe(|| { drop(set.drain_filter(|d| { - PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst); + PREDS.fetch_add(1u32 << d.0, SeqCst); match d.0 { 0 => true, _ => panic!(), @@ -407,8 +408,8 @@ fn drop(&mut self) { })) .ok(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 1); assert_eq!(set.len(), 2); assert_eq!(set.first().unwrap().0, 4); assert_eq!(set.last().unwrap().0, 8); @@ -498,8 +499,6 @@ fn test_extend_ref() { #[test] fn test_recovery() { - use std::cmp::Ordering; - #[derive(Debug)] struct Foo(&'static str, i32); diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 1c183858e7a..85c809e0d18 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1962,7 +1962,7 @@ pub fn remove(&mut self, index: usize) -> Option { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); + /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); /// let buf2 = buf.split_off(1); /// assert_eq!(buf, [1]); /// assert_eq!(buf2, [2, 3]); @@ -2514,10 +2514,10 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result /// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)].into(); /// - /// assert_eq!(deque.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); - /// assert_eq!(deque.binary_search_by_key(&4, |&(a,b)| b), Err(7)); - /// assert_eq!(deque.binary_search_by_key(&100, |&(a,b)| b), Err(13)); - /// let r = deque.binary_search_by_key(&1, |&(a,b)| b); + /// assert_eq!(deque.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(deque.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(deque.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = deque.binary_search_by_key(&1, |&(a, b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` #[unstable(feature = "vecdeque_binary_search", issue = "78021")] diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 392c16546ef..2225bf63e3c 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1041,7 +1041,7 @@ pub fn as_ptr(&self) -> *const T { /// } /// x.set_len(size); /// } - /// assert_eq!(&*x, &[0,1,2,3]); + /// assert_eq!(&*x, &[0, 1, 2, 3]); /// ``` #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[inline] @@ -1594,7 +1594,7 @@ pub fn is_empty(&self) -> bool { /// # Examples /// /// ``` - /// let mut vec = vec![1,2,3]; + /// let mut vec = vec![1, 2, 3]; /// let vec2 = vec.split_off(1); /// assert_eq!(vec, [1]); /// assert_eq!(vec2, [2, 3]); diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 2258d9614d5..339d85902b8 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -50,7 +50,7 @@ impl Layout { /// must not overflow (i.e., the rounded value must be less than /// or equal to `usize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")] #[inline] pub const fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { @@ -96,7 +96,7 @@ pub const fn from_size_align(size: usize, align: usize) -> Result usize { self.size_ @@ -104,7 +104,7 @@ pub const fn size(&self) -> usize { /// The minimum byte alignment for a memory block of this layout. #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")] #[inline] pub const fn align(&self) -> usize { self.align_.get() diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b2afb702eeb..e1b6307613b 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1027,7 +1027,6 @@ impl RefCell { /// # Examples /// /// ``` - /// #![feature(refcell_take)] /// use std::cell::RefCell; /// /// let c = RefCell::new(5); @@ -1036,7 +1035,7 @@ impl RefCell { /// assert_eq!(five, 5); /// assert_eq!(c.into_inner(), 0); /// ``` - #[unstable(feature = "refcell_take", issue = "71395")] + #[stable(feature = "refcell_take", since = "1.50.0")] pub fn take(&self) -> T { self.replace(Default::default()) } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index bbb3a3dea43..47ae1a64190 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -641,14 +641,12 @@ fn min(self, other: Self) -> Self /// # Examples /// /// ``` - /// #![feature(clamp)] - /// /// assert!((-3).clamp(-2, 1) == -2); /// assert!(0.clamp(-2, 1) == 0); /// assert!(2.clamp(-2, 1) == 1); /// ``` #[must_use] - #[unstable(feature = "clamp", issue = "44095")] + #[stable(feature = "clamp", since = "1.50.0")] fn clamp(self, min: Self, max: Self) -> Self where Self: Sized, diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 2e070d71224..9753e1b43ba 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -1,6 +1,5 @@ use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen}; -use crate::ops::Try; -use crate::usize; +use crate::{ops::Try, usize}; /// An iterator that links two iterators together, in a chain. /// diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs new file mode 100644 index 00000000000..7da47dcd2d1 --- /dev/null +++ b/library/core/src/iter/adapters/cloned.rs @@ -0,0 +1,139 @@ +use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::{FusedIterator, TrustedLen}; +use crate::ops::Try; + +/// An iterator that clones the elements of an underlying iterator. +/// +/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cloned`]: Iterator::cloned +/// [`Iterator`]: trait.Iterator.html +#[stable(feature = "iter_cloned", since = "1.1.0")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[derive(Clone, Debug)] +pub struct Cloned { + it: I, +} + +impl Cloned { + pub(in crate::iter) fn new(it: I) -> Cloned { + Cloned { it } + } +} + +fn clone_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { + move |acc, elt| f(acc, elt.clone()) +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> Iterator for Cloned +where + I: Iterator, + T: Clone, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().cloned() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_fold(init, clone_try_fold(f)) + } + + fn fold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.map(T::clone).fold(init, f) + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { try_get_unchecked(&mut self.it, idx).clone() } + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> DoubleEndedIterator for Cloned +where + I: DoubleEndedIterator, + T: Clone, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().cloned() + } + + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_rfold(init, clone_try_fold(f)) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.map(T::clone).rfold(init, f) + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> ExactSizeIterator for Cloned +where + I: ExactSizeIterator, + T: Clone, +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, I, T: 'a> FusedIterator for Cloned +where + I: FusedIterator, + T: Clone, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Cloned +where + I: TrustedRandomAccess, +{ + #[inline] + fn may_have_side_effect() -> bool { + true + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I, T: 'a> TrustedLen for Cloned +where + I: TrustedLen, + T: Clone, +{ +} diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs new file mode 100644 index 00000000000..46f22354111 --- /dev/null +++ b/library/core/src/iter/adapters/copied.rs @@ -0,0 +1,155 @@ +use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::{FusedIterator, TrustedLen}; +use crate::ops::Try; + +/// An iterator that copies the elements of an underlying iterator. +/// +/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`copied`]: Iterator::copied +/// [`Iterator`]: trait.Iterator.html +#[stable(feature = "iter_copied", since = "1.36.0")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[derive(Clone, Debug)] +pub struct Copied { + it: I, +} + +impl Copied { + pub(in crate::iter) fn new(it: I) -> Copied { + Copied { it } + } +} + +fn copy_fold(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc { + move |acc, &elt| f(acc, elt) +} + +fn copy_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { + move |acc, &elt| f(acc, elt) +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> Iterator for Copied +where + I: Iterator, + T: Copy, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().copied() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_fold(init, copy_try_fold(f)) + } + + fn fold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.fold(init, copy_fold(f)) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() + } + + fn last(self) -> Option { + self.it.last().copied() + } + + fn count(self) -> usize { + self.it.count() + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + *unsafe { try_get_unchecked(&mut self.it, idx) } + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> DoubleEndedIterator for Copied +where + I: DoubleEndedIterator, + T: Copy, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().copied() + } + + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_rfold(init, copy_try_fold(f)) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.rfold(init, copy_fold(f)) + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> ExactSizeIterator for Copied +where + I: ExactSizeIterator, + T: Copy, +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> FusedIterator for Copied +where + I: FusedIterator, + T: Copy, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Copied +where + I: TrustedRandomAccess, +{ + #[inline] + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +unsafe impl<'a, I, T: 'a> TrustedLen for Copied +where + I: TrustedLen, + T: Copy, +{ +} diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs new file mode 100644 index 00000000000..6e9a011f819 --- /dev/null +++ b/library/core/src/iter/adapters/cycle.rs @@ -0,0 +1,87 @@ +use crate::{iter::FusedIterator, ops::Try}; + +/// An iterator that repeats endlessly. +/// +/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cycle`]: Iterator::cycle +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Cycle { + orig: I, + iter: I, +} + +impl Cycle { + pub(in crate::iter) fn new(iter: I) -> Cycle { + Cycle { orig: iter.clone(), iter } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Cycle +where + I: Clone + Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + match self.iter.next() { + None => { + self.iter = self.orig.clone(); + self.iter.next() + } + y => y, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // the cycle iterator is either empty or infinite + match self.orig.size_hint() { + sz @ (0, Some(0)) => sz, + (0, _) => (0, None), + _ => (usize::MAX, None), + } + } + + #[inline] + fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + // fully iterate the current iterator. this is necessary because + // `self.iter` may be empty even when `self.orig` isn't + acc = self.iter.try_fold(acc, &mut f)?; + self.iter = self.orig.clone(); + + // complete a full cycle, keeping track of whether the cycled + // iterator is empty or not. we need to return early in case + // of an empty iterator to prevent an infinite loop + let mut is_empty = true; + acc = self.iter.try_fold(acc, |acc, x| { + is_empty = false; + f(acc, x) + })?; + + if is_empty { + return try { acc }; + } + + loop { + self.iter = self.orig.clone(); + acc = self.iter.try_fold(acc, &mut f)?; + } + } + + // No `fold` override, because `fold` doesn't make much sense for `Cycle`, + // and we can't do anything better than the default. +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Cycle where I: Clone + Iterator {} diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs new file mode 100644 index 00000000000..5978c2da98c --- /dev/null +++ b/library/core/src/iter/adapters/enumerate.rs @@ -0,0 +1,238 @@ +use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::{Add, AddAssign, Try}; + +/// An iterator that yields the current count and the element during iteration. +/// +/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`enumerate`]: Iterator::enumerate +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Enumerate { + iter: I, + count: usize, +} +impl Enumerate { + pub(in crate::iter) fn new(iter: I) -> Enumerate { + Enumerate { iter, count: 0 } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Enumerate +where + I: Iterator, +{ + type Item = (usize, ::Item); + + /// # Overflow Behavior + /// + /// The method does no guarding against overflows, so enumerating more than + /// `usize::MAX` elements either produces the wrong result or panics. If + /// debug assertions are enabled, a panic is guaranteed. + /// + /// # Panics + /// + /// Might panic if the index of the element overflows a `usize`. + #[inline] + fn next(&mut self) -> Option<(usize, ::Item)> { + let a = self.iter.next()?; + let i = self.count; + // Possible undefined overflow. + AddAssign::add_assign(&mut self.count, 1); + Some((i, a)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { + let a = self.iter.nth(n)?; + // Possible undefined overflow. + let i = Add::add(self.count, n); + self.count = Add::add(i, 1); + Some((i, a)) + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn enumerate<'a, T, Acc, R>( + count: &'a mut usize, + mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| { + let acc = fold(acc, (*count, item)); + // Possible undefined overflow. + AddAssign::add_assign(count, 1); + acc + } + } + + self.iter.try_fold(init, enumerate(&mut self.count, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + let acc = fold(acc, (count, item)); + // Possible undefined overflow. + AddAssign::add_assign(&mut count, 1); + acc + } + } + + self.iter.fold(init, enumerate(self.count, fold)) + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; + (Add::add(self.count, idx), value) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Enumerate +where + I: ExactSizeIterator + DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<(usize, ::Item)> { + let a = self.iter.next_back()?; + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + Some((self.count + len, a)) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { + let a = self.iter.nth_back(n)?; + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + Some((self.count + len, a)) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + // Can safely add and subtract the count, as `ExactSizeIterator` promises + // that the number of elements fits into a `usize`. + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> R, + ) -> impl FnMut(Acc, T) -> R { + move |acc, item| { + count -= 1; + fold(acc, (count, item)) + } + } + + let count = self.count + self.iter.len(); + self.iter.try_rfold(init, enumerate(count, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + // Can safely add and subtract the count, as `ExactSizeIterator` promises + // that the number of elements fits into a `usize`. + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + count -= 1; + fold(acc, (count, item)) + } + } + + let count = self.count + self.iter.len(); + self.iter.rfold(init, enumerate(count, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Enumerate +where + I: ExactSizeIterator, +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Enumerate +where + I: TrustedRandomAccess, +{ + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Enumerate where I: FusedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Enumerate where I: TrustedLen {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Enumerate +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Enumerate {} diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs new file mode 100644 index 00000000000..f8d684fcdda --- /dev/null +++ b/library/core/src/iter/adapters/filter.rs @@ -0,0 +1,152 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::Try; + +/// An iterator that filters the elements of `iter` with `predicate`. +/// +/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter`]: Iterator::filter +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Filter { + iter: I, + predicate: P, +} +impl Filter { + pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter { + Filter { iter, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Filter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Filter").field("iter", &self.iter).finish() + } +} + +fn filter_fold( + mut predicate: impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } +} + +fn filter_try_fold<'a, T, Acc, R: Try>( + predicate: &'a mut impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Filter +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.find(&mut self.predicate) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + // this special case allows the compiler to make `.filter(_).count()` + // branchless. Barring perfect branch prediction (which is unattainable in + // the general case), this will be much faster in >90% of cases (containing + // virtually all real workloads) and only a tiny bit slower in the rest. + // + // Having this specialization thus allows us to write `.filter(p).count()` + // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is + // less readable and also less backwards-compatible to Rust before 1.10. + // + // Using the branchless version will also simplify the LLVM byte code, thus + // leaving more budget for LLVM optimizations. + #[inline] + fn count(self) -> usize { + #[inline] + fn to_usize(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize { + move |x| predicate(&x) as usize + } + + self.iter.map(to_usize(self.predicate)).sum() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, filter_fold(self.predicate, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Filter +where + P: FnMut(&I::Item) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.rfind(&mut self.predicate) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, filter_fold(self.predicate, fold)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Filter +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Filter where P: FnMut(&I::Item) -> bool {} diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs new file mode 100644 index 00000000000..0dccf2c533b --- /dev/null +++ b/library/core/src/iter/adapters/filter_map.rs @@ -0,0 +1,150 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that uses `f` to both filter and map elements from `iter`. +/// +/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter_map`]: Iterator::filter_map +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct FilterMap { + iter: I, + f: F, +} +impl FilterMap { + pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap { + FilterMap { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for FilterMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FilterMap").field("iter", &self.iter).finish() + } +} + +fn filter_map_fold( + mut f: impl FnMut(T) -> Option, + mut fold: impl FnMut(Acc, B) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => acc, + } +} + +fn filter_map_try_fold<'a, T, B, Acc, R: Try>( + f: &'a mut impl FnMut(T) -> Option, + mut fold: impl FnMut(Acc, B) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => try { acc }, + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for FilterMap +where + F: FnMut(I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.find_map(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, filter_map_fold(self.f, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for FilterMap +where + F: FnMut(I::Item) -> Option, +{ + #[inline] + fn next_back(&mut self) -> Option { + #[inline] + fn find( + f: &mut impl FnMut(T) -> Option, + ) -> impl FnMut((), T) -> ControlFlow + '_ { + move |(), x| match f(x) { + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, + } + } + + self.iter.try_rfold((), find(&mut self.f)).break_value() + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, filter_map_fold(self.f, fold)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for FilterMap +where + F: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for FilterMap where + F: FnMut(I::Item) -> Option +{ +} diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 96d0a60a327..ff85e114dc9 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,9 +1,7 @@ use crate::fmt; +use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map}; use crate::ops::Try; -use super::super::{DoubleEndedIterator, Fuse, FusedIterator, Iterator}; -use super::Map; - /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// @@ -14,8 +12,9 @@ pub struct FlatMap { inner: FlattenCompat, ::IntoIter>, } + impl U> FlatMap { - pub(in super::super) fn new(iter: I, f: F) -> FlatMap { + pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } } diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 60ac3524e66..ae074065315 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,9 +1,6 @@ -use super::InPlaceIterable; use crate::intrinsics; -use crate::iter::adapters::zip::try_get_unchecked; -use crate::iter::adapters::SourceIter; -use crate::iter::TrustedRandomAccess; -use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; +use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter}; +use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedRandomAccess}; use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs new file mode 100644 index 00000000000..88f5ee61b6b --- /dev/null +++ b/library/core/src/iter/adapters/inspect.rs @@ -0,0 +1,167 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::Try; + +/// An iterator that calls a function with a reference to each element before +/// yielding it. +/// +/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`inspect`]: Iterator::inspect +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Inspect { + iter: I, + f: F, +} +impl Inspect { + pub(in crate::iter) fn new(iter: I, f: F) -> Inspect { + Inspect { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Inspect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Inspect").field("iter", &self.iter).finish() + } +} + +impl Inspect +where + F: FnMut(&I::Item), +{ + #[inline] + fn do_inspect(&mut self, elt: Option) -> Option { + if let Some(ref a) = elt { + (self.f)(a); + } + + elt + } +} + +fn inspect_fold( + mut f: impl FnMut(&T), + mut fold: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + f(&item); + fold(acc, item) + } +} + +fn inspect_try_fold<'a, T, Acc, R>( + f: &'a mut impl FnMut(&T), + mut fold: impl FnMut(Acc, T) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| { + f(&item); + fold(acc, item) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Inspect +where + F: FnMut(&I::Item), +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + let next = self.iter.next(); + self.do_inspect(next) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, inspect_fold(self.f, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Inspect +where + F: FnMut(&I::Item), +{ + #[inline] + fn next_back(&mut self) -> Option { + let next = self.iter.next_back(); + self.do_inspect(next) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, inspect_fold(self.f, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Inspect +where + F: FnMut(&I::Item), +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Inspect where F: FnMut(&I::Item) {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Inspect +where + F: FnMut(&I::Item), + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Inspect where F: FnMut(&I::Item) {} diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs new file mode 100644 index 00000000000..12673806ec4 --- /dev/null +++ b/library/core/src/iter/adapters/map.rs @@ -0,0 +1,213 @@ +use crate::fmt; +use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::Try; + +/// An iterator that maps the values of `iter` with `f`. +/// +/// This `struct` is created by the [`map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`map`]: Iterator::map +/// [`Iterator`]: trait.Iterator.html +/// +/// # Notes about side effects +/// +/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that +/// you can also [`map`] backwards: +/// +/// ```rust +/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); +/// +/// assert_eq!(v, [4, 3, 2]); +/// ``` +/// +/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html +/// +/// But if your closure has state, iterating backwards may act in a way you do +/// not expect. Let's go through an example. First, in the forward direction: +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) { +/// println!("{:?}", pair); +/// } +/// ``` +/// +/// This will print "('a', 1), ('b', 2), ('c', 3)". +/// +/// Now consider this twist where we add a call to `rev`. This version will +/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, +/// but the values of the counter still go in order. This is because `map()` is +/// still being called lazily on each item, but we are popping items off the +/// back of the vector now, instead of shifting them from the front. +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) +/// .rev() { +/// println!("{:?}", pair); +/// } +/// ``` +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Map { + iter: I, + f: F, +} +impl Map { + pub(in crate::iter) fn new(iter: I, f: F) -> Map { + Map { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Map { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Map").field("iter", &self.iter).finish() + } +} + +fn map_fold( + mut f: impl FnMut(T) -> B, + mut g: impl FnMut(Acc, B) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, elt| g(acc, f(elt)) +} + +fn map_try_fold<'a, T, B, Acc, R>( + f: &'a mut impl FnMut(T) -> B, + mut g: impl FnMut(Acc, B) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, elt| g(acc, f(elt)) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Map +where + F: FnMut(I::Item) -> B, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn try_fold(&mut self, init: Acc, g: G) -> R + where + Self: Sized, + G: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, map_try_fold(&mut self.f, g)) + } + + fn fold(self, init: Acc, g: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, map_fold(self.f, g)) + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Map +where + F: FnMut(I::Item) -> B, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(&mut self.f) + } + + fn try_rfold(&mut self, init: Acc, g: G) -> R + where + Self: Sized, + G: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) + } + + fn rfold(self, init: Acc, g: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, map_fold(self.f, g)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Map +where + F: FnMut(I::Item) -> B, +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Map where F: FnMut(I::Item) -> B {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Map +where + I: TrustedLen, + F: FnMut(I::Item) -> B, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Map +where + I: TrustedRandomAccess, +{ + #[inline] + fn may_have_side_effect() -> bool { + true + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Map +where + F: FnMut(I::Item) -> B, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Map where F: FnMut(I::Item) -> B {} diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs new file mode 100644 index 00000000000..26114d53284 --- /dev/null +++ b/library/core/src/iter/adapters/map_while.rs @@ -0,0 +1,101 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that only accepts elements while `predicate` returns `Some(_)`. +/// +/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`map_while`]: Iterator::map_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[derive(Clone)] +pub struct MapWhile { + iter: I, + predicate: P, +} + +impl MapWhile { + pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile { + MapWhile { iter, predicate } + } +} + +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +impl fmt::Debug for MapWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("MapWhile").field("iter", &self.iter).finish() + } +} + +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +impl Iterator for MapWhile +where + P: FnMut(I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + let x = self.iter.next()?; + (self.predicate)(x) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + let Self { iter, predicate } = self; + iter.try_fold(init, |acc, x| match predicate(x) { + Some(item) => ControlFlow::from_try(fold(acc, item)), + None => ControlFlow::Break(try { acc }), + }) + .into_try() + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for MapWhile +where + P: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for MapWhile where + P: FnMut(I::Item) -> Option +{ +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 9586284e1d7..5ef5717085e 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,26 +1,51 @@ -use crate::cmp; -use crate::fmt; -use crate::intrinsics; -use crate::ops::{Add, AddAssign, ControlFlow, Try}; - -use super::from_fn; -use super::{ - DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, TrustedLen, -}; +use crate::iter::{InPlaceIterable, Iterator}; +use crate::ops::{ControlFlow, Try}; mod chain; +mod cloned; +mod copied; +mod cycle; +mod enumerate; +mod filter; +mod filter_map; mod flatten; mod fuse; +mod inspect; +mod map; +mod map_while; +mod peekable; +mod rev; +mod scan; +mod skip; +mod skip_while; +mod step_by; +mod take; +mod take_while; mod zip; -pub use self::chain::Chain; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::flatten::{FlatMap, Flatten}; -pub use self::fuse::Fuse; -use self::zip::try_get_unchecked; +pub use self::{ + chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap, + flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev, + scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip, +}; + +#[stable(feature = "iter_cloned", since = "1.1.0")] +pub use self::cloned::Cloned; + +#[stable(feature = "iterator_step_by", since = "1.28.0")] +pub use self::step_by::StepBy; + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +pub use self::flatten::Flatten; + +#[stable(feature = "iter_copied", since = "1.36.0")] +pub use self::copied::Copied; + +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +pub use self::map_while::MapWhile; + #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::zip::TrustedRandomAccess; -pub use self::zip::Zip; /// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that @@ -89,2810 +114,6 @@ pub unsafe trait SourceIter { unsafe fn as_inner(&mut self) -> &mut Self::Source; } -/// A double-ended iterator with the direction inverted. -/// -/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`rev`]: Iterator::rev -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Rev { - iter: T, -} -impl Rev { - pub(super) fn new(iter: T) -> Rev { - Rev { iter } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Rev -where - I: DoubleEndedIterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - self.iter.next_back() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - self.iter.advance_back_by(n) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<::Item> { - self.iter.nth_back(n) - } - - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, f) - } - - fn fold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, f) - } - - #[inline] - fn find

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.iter.rfind(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Rev -where - I: DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option<::Item> { - self.iter.next() - } - - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - self.iter.advance_by(n) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<::Item> { - self.iter.nth(n) - } - - fn try_rfold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, f) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, f) - } - - fn rfind

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.iter.find(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Rev -where - I: ExactSizeIterator + DoubleEndedIterator, -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Rev where I: TrustedLen + DoubleEndedIterator {} - -/// An iterator that copies the elements of an underlying iterator. -/// -/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`copied`]: Iterator::copied -/// [`Iterator`]: trait.Iterator.html -#[stable(feature = "iter_copied", since = "1.36.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Clone, Debug)] -pub struct Copied { - it: I, -} - -impl Copied { - pub(super) fn new(it: I) -> Copied { - Copied { it } - } -} - -fn copy_fold(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc { - move |acc, &elt| f(acc, elt) -} - -fn copy_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { - move |acc, &elt| f(acc, elt) -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> Iterator for Copied -where - I: Iterator, - T: Copy, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.it.next().copied() - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } - - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_fold(init, copy_try_fold(f)) - } - - fn fold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.fold(init, copy_fold(f)) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() - } - - fn last(self) -> Option { - self.it.last().copied() - } - - fn count(self) -> usize { - self.it.count() - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - *unsafe { try_get_unchecked(&mut self.it, idx) } - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> DoubleEndedIterator for Copied -where - I: DoubleEndedIterator, - T: Copy, -{ - fn next_back(&mut self) -> Option { - self.it.next_back().copied() - } - - fn try_rfold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_rfold(init, copy_try_fold(f)) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.rfold(init, copy_fold(f)) - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> ExactSizeIterator for Copied -where - I: ExactSizeIterator, - T: Copy, -{ - fn len(&self) -> usize { - self.it.len() - } - - fn is_empty(&self) -> bool { - self.it.is_empty() - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> FusedIterator for Copied -where - I: FusedIterator, - T: Copy, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Copied -where - I: TrustedRandomAccess, -{ - #[inline] - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -unsafe impl<'a, I, T: 'a> TrustedLen for Copied -where - I: TrustedLen, - T: Copy, -{ -} - -/// An iterator that clones the elements of an underlying iterator. -/// -/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`cloned`]: Iterator::cloned -/// [`Iterator`]: trait.Iterator.html -#[stable(feature = "iter_cloned", since = "1.1.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Clone, Debug)] -pub struct Cloned { - it: I, -} -impl Cloned { - pub(super) fn new(it: I) -> Cloned { - Cloned { it } - } -} - -fn clone_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { - move |acc, elt| f(acc, elt.clone()) -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> Iterator for Cloned -where - I: Iterator, - T: Clone, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.it.next().cloned() - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } - - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_fold(init, clone_try_fold(f)) - } - - fn fold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.map(T::clone).fold(init, f) - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { try_get_unchecked(&mut self.it, idx).clone() } - } -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> DoubleEndedIterator for Cloned -where - I: DoubleEndedIterator, - T: Clone, -{ - fn next_back(&mut self) -> Option { - self.it.next_back().cloned() - } - - fn try_rfold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_rfold(init, clone_try_fold(f)) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.map(T::clone).rfold(init, f) - } -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> ExactSizeIterator for Cloned -where - I: ExactSizeIterator, - T: Clone, -{ - fn len(&self) -> usize { - self.it.len() - } - - fn is_empty(&self) -> bool { - self.it.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, I, T: 'a> FusedIterator for Cloned -where - I: FusedIterator, - T: Clone, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Cloned -where - I: TrustedRandomAccess, -{ - #[inline] - fn may_have_side_effect() -> bool { - true - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, I, T: 'a> TrustedLen for Cloned -where - I: TrustedLen, - T: Clone, -{ -} - -/// An iterator that repeats endlessly. -/// -/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`cycle`]: Iterator::cycle -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Cycle { - orig: I, - iter: I, -} -impl Cycle { - pub(super) fn new(iter: I) -> Cycle { - Cycle { orig: iter.clone(), iter } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Cycle -where - I: Clone + Iterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - match self.iter.next() { - None => { - self.iter = self.orig.clone(); - self.iter.next() - } - y => y, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // the cycle iterator is either empty or infinite - match self.orig.size_hint() { - sz @ (0, Some(0)) => sz, - (0, _) => (0, None), - _ => (usize::MAX, None), - } - } - - #[inline] - fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R - where - F: FnMut(Acc, Self::Item) -> R, - R: Try, - { - // fully iterate the current iterator. this is necessary because - // `self.iter` may be empty even when `self.orig` isn't - acc = self.iter.try_fold(acc, &mut f)?; - self.iter = self.orig.clone(); - - // complete a full cycle, keeping track of whether the cycled - // iterator is empty or not. we need to return early in case - // of an empty iterator to prevent an infinite loop - let mut is_empty = true; - acc = self.iter.try_fold(acc, |acc, x| { - is_empty = false; - f(acc, x) - })?; - - if is_empty { - return try { acc }; - } - - loop { - self.iter = self.orig.clone(); - acc = self.iter.try_fold(acc, &mut f)?; - } - } - - // No `fold` override, because `fold` doesn't make much sense for `Cycle`, - // and we can't do anything better than the default. -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Cycle where I: Clone + Iterator {} - -/// An iterator for stepping iterators by a custom amount. -/// -/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See -/// its documentation for more. -/// -/// [`step_by`]: Iterator::step_by -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "iterator_step_by", since = "1.28.0")] -#[derive(Clone, Debug)] -pub struct StepBy { - iter: I, - step: usize, - first_take: bool, -} -impl StepBy { - pub(super) fn new(iter: I, step: usize) -> StepBy { - assert!(step != 0); - StepBy { iter, step: step - 1, first_take: true } - } -} - -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl Iterator for StepBy -where - I: Iterator, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.first_take { - self.first_take = false; - self.iter.next() - } else { - self.iter.nth(self.step) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - #[inline] - fn first_size(step: usize) -> impl Fn(usize) -> usize { - move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } - } - - #[inline] - fn other_size(step: usize) -> impl Fn(usize) -> usize { - move |n| n / (step + 1) - } - - let (low, high) = self.iter.size_hint(); - - if self.first_take { - let f = first_size(self.step); - (f(low), high.map(f)) - } else { - let f = other_size(self.step); - (f(low), high.map(f)) - } - } - - #[inline] - fn nth(&mut self, mut n: usize) -> Option { - if self.first_take { - self.first_take = false; - let first = self.iter.next(); - if n == 0 { - return first; - } - n -= 1; - } - // n and self.step are indices, we need to add 1 to get the amount of elements - // When calling `.nth`, we need to subtract 1 again to convert back to an index - // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` - let mut step = self.step + 1; - // n + 1 could overflow - // thus, if n is usize::MAX, instead of adding one, we call .nth(step) - if n == usize::MAX { - self.iter.nth(step - 1); - } else { - n += 1; - } - - // overflow handling - loop { - let mul = n.checked_mul(step); - { - if intrinsics::likely(mul.is_some()) { - return self.iter.nth(mul.unwrap() - 1); - } - } - let div_n = usize::MAX / n; - let div_step = usize::MAX / step; - let nth_n = div_n * n; - let nth_step = div_step * step; - let nth = if nth_n > nth_step { - step -= div_n; - nth_n - } else { - n -= div_step; - nth_step - }; - self.iter.nth(nth - 1); - } - } - - fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R - where - F: FnMut(Acc, Self::Item) -> R, - R: Try, - { - #[inline] - fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { - move || iter.nth(step) - } - - if self.first_take { - self.first_take = false; - match self.iter.next() { - None => return try { acc }, - Some(x) => acc = f(acc, x)?, - } - } - from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) - } - - fn fold(mut self, mut acc: Acc, mut f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { - move || iter.nth(step) - } - - if self.first_take { - self.first_take = false; - match self.iter.next() { - None => return acc, - Some(x) => acc = f(acc, x), - } - } - from_fn(nth(&mut self.iter, self.step)).fold(acc, f) - } -} - -impl StepBy -where - I: ExactSizeIterator, -{ - // The zero-based index starting from the end of the iterator of the - // last element. Used in the `DoubleEndedIterator` implementation. - fn next_back_index(&self) -> usize { - let rem = self.iter.len() % (self.step + 1); - if self.first_take { - if rem == 0 { self.step } else { rem - 1 } - } else { - rem - } - } -} - -#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] -impl DoubleEndedIterator for StepBy -where - I: DoubleEndedIterator + ExactSizeIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.nth_back(self.next_back_index()) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - // `self.iter.nth_back(usize::MAX)` does the right thing here when `n` - // is out of bounds because the length of `self.iter` does not exceed - // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is - // zero-indexed - let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index()); - self.iter.nth_back(n) - } - - fn try_rfold(&mut self, init: Acc, mut f: F) -> R - where - F: FnMut(Acc, Self::Item) -> R, - R: Try, - { - #[inline] - fn nth_back( - iter: &mut I, - step: usize, - ) -> impl FnMut() -> Option + '_ { - move || iter.nth_back(step) - } - - match self.next_back() { - None => try { init }, - Some(x) => { - let acc = f(init, x)?; - from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) - } - } - } - - #[inline] - fn rfold(mut self, init: Acc, mut f: F) -> Acc - where - Self: Sized, - F: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn nth_back( - iter: &mut I, - step: usize, - ) -> impl FnMut() -> Option + '_ { - move || iter.nth_back(step) - } - - match self.next_back() { - None => init, - Some(x) => { - let acc = f(init, x); - from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f) - } - } - } -} - -// StepBy can only make the iterator shorter, so the len will still fit. -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} - -/// An iterator that maps the values of `iter` with `f`. -/// -/// This `struct` is created by the [`map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`map`]: Iterator::map -/// [`Iterator`]: trait.Iterator.html -/// -/// # Notes about side effects -/// -/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that -/// you can also [`map`] backwards: -/// -/// ```rust -/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); -/// -/// assert_eq!(v, [4, 3, 2]); -/// ``` -/// -/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html -/// -/// But if your closure has state, iterating backwards may act in a way you do -/// not expect. Let's go through an example. First, in the forward direction: -/// -/// ```rust -/// let mut c = 0; -/// -/// for pair in vec!['a', 'b', 'c'].into_iter() -/// .map(|letter| { c += 1; (letter, c) }) { -/// println!("{:?}", pair); -/// } -/// ``` -/// -/// This will print "('a', 1), ('b', 2), ('c', 3)". -/// -/// Now consider this twist where we add a call to `rev`. This version will -/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, -/// but the values of the counter still go in order. This is because `map()` is -/// still being called lazily on each item, but we are popping items off the -/// back of the vector now, instead of shifting them from the front. -/// -/// ```rust -/// let mut c = 0; -/// -/// for pair in vec!['a', 'b', 'c'].into_iter() -/// .map(|letter| { c += 1; (letter, c) }) -/// .rev() { -/// println!("{:?}", pair); -/// } -/// ``` -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Map { - iter: I, - f: F, -} -impl Map { - pub(super) fn new(iter: I, f: F) -> Map { - Map { iter, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Map { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Map").field("iter", &self.iter).finish() - } -} - -fn map_fold( - mut f: impl FnMut(T) -> B, - mut g: impl FnMut(Acc, B) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, elt| g(acc, f(elt)) -} - -fn map_try_fold<'a, T, B, Acc, R>( - f: &'a mut impl FnMut(T) -> B, - mut g: impl FnMut(Acc, B) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, elt| g(acc, f(elt)) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Map -where - F: FnMut(I::Item) -> B, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(&mut self.f) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn try_fold(&mut self, init: Acc, g: G) -> R - where - Self: Sized, - G: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, map_try_fold(&mut self.f, g)) - } - - fn fold(self, init: Acc, g: G) -> Acc - where - G: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, map_fold(self.f, g)) - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Map -where - F: FnMut(I::Item) -> B, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(&mut self.f) - } - - fn try_rfold(&mut self, init: Acc, g: G) -> R - where - Self: Sized, - G: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) - } - - fn rfold(self, init: Acc, g: G) -> Acc - where - G: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, map_fold(self.f, g)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Map -where - F: FnMut(I::Item) -> B, -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Map where F: FnMut(I::Item) -> B {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Map -where - I: TrustedLen, - F: FnMut(I::Item) -> B, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Map -where - I: TrustedRandomAccess, -{ - #[inline] - fn may_have_side_effect() -> bool { - true - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Map -where - F: FnMut(I::Item) -> B, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Map where F: FnMut(I::Item) -> B {} - -/// An iterator that filters the elements of `iter` with `predicate`. -/// -/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter`]: Iterator::filter -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Filter { - iter: I, - predicate: P, -} -impl Filter { - pub(super) fn new(iter: I, predicate: P) -> Filter { - Filter { iter, predicate } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Filter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Filter").field("iter", &self.iter).finish() - } -} - -fn filter_fold( - mut predicate: impl FnMut(&T) -> bool, - mut fold: impl FnMut(Acc, T) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } -} - -fn filter_try_fold<'a, T, Acc, R: Try>( - predicate: &'a mut impl FnMut(&T) -> bool, - mut fold: impl FnMut(Acc, T) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Filter -where - P: FnMut(&I::Item) -> bool, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.find(&mut self.predicate) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - // this special case allows the compiler to make `.filter(_).count()` - // branchless. Barring perfect branch prediction (which is unattainable in - // the general case), this will be much faster in >90% of cases (containing - // virtually all real workloads) and only a tiny bit slower in the rest. - // - // Having this specialization thus allows us to write `.filter(p).count()` - // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is - // less readable and also less backwards-compatible to Rust before 1.10. - // - // Using the branchless version will also simplify the LLVM byte code, thus - // leaving more budget for LLVM optimizations. - #[inline] - fn count(self) -> usize { - #[inline] - fn to_usize(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize { - move |x| predicate(&x) as usize - } - - self.iter.map(to_usize(self.predicate)).sum() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, filter_fold(self.predicate, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Filter -where - P: FnMut(&I::Item) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.rfind(&mut self.predicate) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, filter_fold(self.predicate, fold)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Filter -where - P: FnMut(&I::Item) -> bool, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Filter where P: FnMut(&I::Item) -> bool {} - -/// An iterator that uses `f` to both filter and map elements from `iter`. -/// -/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter_map`]: Iterator::filter_map -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct FilterMap { - iter: I, - f: F, -} -impl FilterMap { - pub(super) fn new(iter: I, f: F) -> FilterMap { - FilterMap { iter, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FilterMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FilterMap").field("iter", &self.iter).finish() - } -} - -fn filter_map_fold( - mut f: impl FnMut(T) -> Option, - mut fold: impl FnMut(Acc, B) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => acc, - } -} - -fn filter_map_try_fold<'a, T, B, Acc, R: Try>( - f: &'a mut impl FnMut(T) -> Option, - mut fold: impl FnMut(Acc, B) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => try { acc }, - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FilterMap -where - F: FnMut(I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - self.iter.find_map(&mut self.f) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, filter_map_fold(self.f, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FilterMap -where - F: FnMut(I::Item) -> Option, -{ - #[inline] - fn next_back(&mut self) -> Option { - #[inline] - fn find( - f: &mut impl FnMut(T) -> Option, - ) -> impl FnMut((), T) -> ControlFlow + '_ { - move |(), x| match f(x) { - Some(x) => ControlFlow::Break(x), - None => ControlFlow::CONTINUE, - } - } - - self.iter.try_rfold((), find(&mut self.f)).break_value() - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, filter_map_fold(self.f, fold)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for FilterMap -where - F: FnMut(I::Item) -> Option, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for FilterMap where - F: FnMut(I::Item) -> Option -{ -} - -/// An iterator that yields the current count and the element during iteration. -/// -/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`enumerate`]: Iterator::enumerate -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Enumerate { - iter: I, - count: usize, -} -impl Enumerate { - pub(super) fn new(iter: I) -> Enumerate { - Enumerate { iter, count: 0 } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Enumerate -where - I: Iterator, -{ - type Item = (usize, ::Item); - - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so enumerating more than - /// `usize::MAX` elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. - /// - /// # Panics - /// - /// Might panic if the index of the element overflows a `usize`. - #[inline] - fn next(&mut self) -> Option<(usize, ::Item)> { - let a = self.iter.next()?; - let i = self.count; - // Possible undefined overflow. - AddAssign::add_assign(&mut self.count, 1); - Some((i, a)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { - let a = self.iter.nth(n)?; - // Possible undefined overflow. - let i = Add::add(self.count, n); - self.count = Add::add(i, 1); - Some((i, a)) - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - #[inline] - fn enumerate<'a, T, Acc, R>( - count: &'a mut usize, - mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a, - ) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| { - let acc = fold(acc, (*count, item)); - // Possible undefined overflow. - AddAssign::add_assign(count, 1); - acc - } - } - - self.iter.try_fold(init, enumerate(&mut self.count, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn enumerate( - mut count: usize, - mut fold: impl FnMut(Acc, (usize, T)) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| { - let acc = fold(acc, (count, item)); - // Possible undefined overflow. - AddAssign::add_assign(&mut count, 1); - acc - } - } - - self.iter.fold(init, enumerate(self.count, fold)) - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; - (Add::add(self.count, idx), value) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Enumerate -where - I: ExactSizeIterator + DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option<(usize, ::Item)> { - let a = self.iter.next_back()?; - let len = self.iter.len(); - // Can safely add, `ExactSizeIterator` promises that the number of - // elements fits into a `usize`. - Some((self.count + len, a)) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { - let a = self.iter.nth_back(n)?; - let len = self.iter.len(); - // Can safely add, `ExactSizeIterator` promises that the number of - // elements fits into a `usize`. - Some((self.count + len, a)) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - // Can safely add and subtract the count, as `ExactSizeIterator` promises - // that the number of elements fits into a `usize`. - fn enumerate( - mut count: usize, - mut fold: impl FnMut(Acc, (usize, T)) -> R, - ) -> impl FnMut(Acc, T) -> R { - move |acc, item| { - count -= 1; - fold(acc, (count, item)) - } - } - - let count = self.count + self.iter.len(); - self.iter.try_rfold(init, enumerate(count, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - // Can safely add and subtract the count, as `ExactSizeIterator` promises - // that the number of elements fits into a `usize`. - fn enumerate( - mut count: usize, - mut fold: impl FnMut(Acc, (usize, T)) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| { - count -= 1; - fold(acc, (count, item)) - } - } - - let count = self.count + self.iter.len(); - self.iter.rfold(init, enumerate(count, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Enumerate -where - I: ExactSizeIterator, -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Enumerate -where - I: TrustedRandomAccess, -{ - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Enumerate where I: FusedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Enumerate where I: TrustedLen {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Enumerate -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Enumerate {} - -/// An iterator with a `peek()` that returns an optional reference to the next -/// element. -/// -/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`peekable`]: Iterator::peekable -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Peekable { - iter: I, - /// Remember a peeked value, even if it was None. - peeked: Option>, -} -impl Peekable { - pub(super) fn new(iter: I) -> Peekable { - Peekable { iter, peeked: None } - } -} - -// Peekable must remember if a None has been seen in the `.peek()` method. -// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the -// underlying iterator at most once. This does not by itself make the iterator -// fused. -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Peekable { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.peeked.take() { - Some(v) => v, - None => self.iter.next(), - } - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn count(mut self) -> usize { - match self.peeked.take() { - Some(None) => 0, - Some(Some(_)) => 1 + self.iter.count(), - None => self.iter.count(), - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - match self.peeked.take() { - Some(None) => None, - Some(v @ Some(_)) if n == 0 => v, - Some(Some(_)) => self.iter.nth(n - 1), - None => self.iter.nth(n), - } - } - - #[inline] - fn last(mut self) -> Option { - let peek_opt = match self.peeked.take() { - Some(None) => return None, - Some(v) => v, - None => None, - }; - self.iter.last().or(peek_opt) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let peek_len = match self.peeked { - Some(None) => return (0, Some(0)), - Some(Some(_)) => 1, - None => 0, - }; - let (lo, hi) = self.iter.size_hint(); - let lo = lo.saturating_add(peek_len); - let hi = match hi { - Some(x) => x.checked_add(peek_len), - None => None, - }; - (lo, hi) - } - - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - let acc = match self.peeked.take() { - Some(None) => return try { init }, - Some(Some(v)) => f(init, v)?, - None => init, - }; - self.iter.try_fold(acc, f) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - let acc = match self.peeked { - Some(None) => return init, - Some(Some(v)) => fold(init, v), - None => init, - }; - self.iter.fold(acc, fold) - } -} - -#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")] -impl DoubleEndedIterator for Peekable -where - I: DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - match self.peeked.as_mut() { - Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()), - Some(None) => None, - None => self.iter.next_back(), - } - } - - #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - match self.peeked.take() { - Some(None) => try { init }, - Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { - Ok(acc) => f(acc, v), - Err(e) => { - self.peeked = Some(Some(v)); - Try::from_error(e) - } - }, - None => self.iter.try_rfold(init, f), - } - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - match self.peeked { - Some(None) => init, - Some(Some(v)) => { - let acc = self.iter.rfold(init, &mut fold); - fold(acc, v) - } - None => self.iter.rfold(init, fold), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Peekable {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Peekable {} - -impl Peekable { - /// Returns a reference to the next() value without advancing the iterator. - /// - /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. - /// But if the iteration is over, `None` is returned. - /// - /// [`next`]: Iterator::next - /// - /// Because `peek()` returns a reference, and many iterators iterate over - /// references, there can be a possibly confusing situation where the - /// return value is a double reference. You can see this effect in the - /// examples below. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let xs = [1, 2, 3]; - /// - /// let mut iter = xs.iter().peekable(); - /// - /// // peek() lets us see into the future - /// assert_eq!(iter.peek(), Some(&&1)); - /// assert_eq!(iter.next(), Some(&1)); - /// - /// assert_eq!(iter.next(), Some(&2)); - /// - /// // The iterator does not advance even if we `peek` multiple times - /// assert_eq!(iter.peek(), Some(&&3)); - /// assert_eq!(iter.peek(), Some(&&3)); - /// - /// assert_eq!(iter.next(), Some(&3)); - /// - /// // After the iterator is finished, so is `peek()` - /// assert_eq!(iter.peek(), None); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn peek(&mut self) -> Option<&I::Item> { - let iter = &mut self.iter; - self.peeked.get_or_insert_with(|| iter.next()).as_ref() - } - - /// Consume and return the next value of this iterator if a condition is true. - /// - /// If `func` returns `true` for the next value of this iterator, consume and return it. - /// Otherwise, return `None`. - /// - /// # Examples - /// Consume a number if it's equal to 0. - /// ``` - /// #![feature(peekable_next_if)] - /// let mut iter = (0..5).peekable(); - /// // The first item of the iterator is 0; consume it. - /// assert_eq!(iter.next_if(|&x| x == 0), Some(0)); - /// // The next item returned is now 1, so `consume` will return `false`. - /// assert_eq!(iter.next_if(|&x| x == 0), None); - /// // `next_if` saves the value of the next item if it was not equal to `expected`. - /// assert_eq!(iter.next(), Some(1)); - /// ``` - /// - /// Consume any number less than 10. - /// ``` - /// #![feature(peekable_next_if)] - /// let mut iter = (1..20).peekable(); - /// // Consume all numbers less than 10 - /// while iter.next_if(|&x| x < 10).is_some() {} - /// // The next value returned will be 10 - /// assert_eq!(iter.next(), Some(10)); - /// ``` - #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { - match self.next() { - Some(matched) if func(&matched) => Some(matched), - other => { - // Since we called `self.next()`, we consumed `self.peeked`. - assert!(self.peeked.is_none()); - self.peeked = Some(other); - None - } - } - } - - /// Consume and return the next item if it is equal to `expected`. - /// - /// # Example - /// Consume a number if it's equal to 0. - /// ``` - /// #![feature(peekable_next_if)] - /// let mut iter = (0..5).peekable(); - /// // The first item of the iterator is 0; consume it. - /// assert_eq!(iter.next_if_eq(&0), Some(0)); - /// // The next item returned is now 1, so `consume` will return `false`. - /// assert_eq!(iter.next_if_eq(&0), None); - /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. - /// assert_eq!(iter.next(), Some(1)); - /// ``` - #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if_eq(&mut self, expected: &T) -> Option - where - T: ?Sized, - I::Item: PartialEq, - { - self.next_if(|next| next == expected) - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Peekable where I: TrustedLen {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Peekable -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Peekable {} - -/// An iterator that rejects elements while `predicate` returns `true`. -/// -/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`skip_while`]: Iterator::skip_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct SkipWhile { - iter: I, - flag: bool, - predicate: P, -} -impl SkipWhile { - pub(super) fn new(iter: I, predicate: P) -> SkipWhile { - SkipWhile { iter, flag: false, predicate } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SkipWhile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for SkipWhile -where - P: FnMut(&I::Item) -> bool, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - fn check<'a, T>( - flag: &'a mut bool, - pred: &'a mut impl FnMut(&T) -> bool, - ) -> impl FnMut(&T) -> bool + 'a { - move |x| { - if *flag || !pred(x) { - *flag = true; - true - } else { - false - } - } - } - - let flag = &mut self.flag; - let pred = &mut self.predicate; - self.iter.find(check(flag, pred)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - if !self.flag { - match self.next() { - Some(v) => init = fold(init, v)?, - None => return try { init }, - } - } - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(mut self, mut init: Acc, mut fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if !self.flag { - match self.next() { - Some(v) => init = fold(init, v), - None => return init, - } - } - self.iter.fold(init, fold) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SkipWhile -where - I: FusedIterator, - P: FnMut(&I::Item) -> bool, -{ -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for SkipWhile -where - P: FnMut(&I::Item) -> bool, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for SkipWhile where - F: FnMut(&I::Item) -> bool -{ -} - -/// An iterator that only accepts elements while `predicate` returns `true`. -/// -/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take_while`]: Iterator::take_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct TakeWhile { - iter: I, - flag: bool, - predicate: P, -} -impl TakeWhile { - pub(super) fn new(iter: I, predicate: P) -> TakeWhile { - TakeWhile { iter, flag: false, predicate } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for TakeWhile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for TakeWhile -where - P: FnMut(&I::Item) -> bool, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.flag { - None - } else { - let x = self.iter.next()?; - if (self.predicate)(&x) { - Some(x) - } else { - self.flag = true; - None - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.flag { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn check<'a, T, Acc, R: Try>( - flag: &'a mut bool, - p: &'a mut impl FnMut(&T) -> bool, - mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { - move |acc, x| { - if p(&x) { - ControlFlow::from_try(fold(acc, x)) - } else { - *flag = true; - ControlFlow::Break(try { acc }) - } - } - } - - if self.flag { - try { init } - } else { - let flag = &mut self.flag; - let p = &mut self.predicate; - self.iter.try_fold(init, check(flag, p, fold)).into_try() - } - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for TakeWhile -where - I: FusedIterator, - P: FnMut(&I::Item) -> bool, -{ -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for TakeWhile -where - P: FnMut(&I::Item) -> bool, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for TakeWhile where - F: FnMut(&I::Item) -> bool -{ -} - -/// An iterator that only accepts elements while `predicate` returns `Some(_)`. -/// -/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`map_while`]: Iterator::map_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] -#[derive(Clone)] -pub struct MapWhile { - iter: I, - predicate: P, -} - -impl MapWhile { - pub(super) fn new(iter: I, predicate: P) -> MapWhile { - MapWhile { iter, predicate } - } -} - -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] -impl fmt::Debug for MapWhile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MapWhile").field("iter", &self.iter).finish() - } -} - -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] -impl Iterator for MapWhile -where - P: FnMut(I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - let x = self.iter.next()?; - (self.predicate)(x) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - let Self { iter, predicate } = self; - iter.try_fold(init, |acc, x| match predicate(x) { - Some(item) => ControlFlow::from_try(fold(acc, item)), - None => ControlFlow::Break(try { acc }), - }) - .into_try() - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for MapWhile -where - P: FnMut(I::Item) -> Option, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for MapWhile where - P: FnMut(I::Item) -> Option -{ -} - -/// An iterator that skips over `n` elements of `iter`. -/// -/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`skip`]: Iterator::skip -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Skip { - iter: I, - n: usize, -} -impl Skip { - pub(super) fn new(iter: I, n: usize) -> Skip { - Skip { iter, n } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Skip -where - I: Iterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.n == 0 { - self.iter.next() - } else { - let old_n = self.n; - self.n = 0; - self.iter.nth(old_n) - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - // Can't just add n + self.n due to overflow. - if self.n > 0 { - let to_skip = self.n; - self.n = 0; - // nth(n) skips n+1 - self.iter.nth(to_skip - 1)?; - } - self.iter.nth(n) - } - - #[inline] - fn count(mut self) -> usize { - if self.n > 0 { - // nth(n) skips n+1 - if self.iter.nth(self.n - 1).is_none() { - return 0; - } - } - self.iter.count() - } - - #[inline] - fn last(mut self) -> Option { - if self.n > 0 { - // nth(n) skips n+1 - self.iter.nth(self.n - 1)?; - } - self.iter.last() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.iter.size_hint(); - - let lower = lower.saturating_sub(self.n); - let upper = match upper { - Some(x) => Some(x.saturating_sub(self.n)), - None => None, - }; - - (lower, upper) - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - let n = self.n; - self.n = 0; - if n > 0 { - // nth(n) skips n+1 - if self.iter.nth(n - 1).is_none() { - return try { init }; - } - } - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.n > 0 { - // nth(n) skips n+1 - if self.iter.nth(self.n - 1).is_none() { - return init; - } - } - self.iter.fold(init, fold) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Skip where I: ExactSizeIterator {} - -#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")] -impl DoubleEndedIterator for Skip -where - I: DoubleEndedIterator + ExactSizeIterator, -{ - fn next_back(&mut self) -> Option { - if self.len() > 0 { self.iter.next_back() } else { None } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n < len { - self.iter.nth_back(n) - } else { - if len > 0 { - // consume the original iterator - self.iter.nth_back(len - 1); - } - None - } - } - - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn check>( - mut n: usize, - mut fold: impl FnMut(Acc, T) -> R, - ) -> impl FnMut(Acc, T) -> ControlFlow { - move |acc, x| { - n -= 1; - let r = fold(acc, x); - if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } - } - } - - let n = self.len(); - if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } - } - - fn rfold(mut self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_rfold(init, ok(fold)).unwrap() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Skip where I: FusedIterator {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Skip -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Skip {} - -/// An iterator that only iterates over the first `n` iterations of `iter`. -/// -/// This `struct` is created by the [`take`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take`]: Iterator::take -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Take { - pub(super) iter: I, - pub(super) n: usize, -} -impl Take { - pub(super) fn new(iter: I, n: usize) -> Take { - Take { iter, n } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Take -where - I: Iterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - if self.n != 0 { - self.n -= 1; - self.iter.next() - } else { - None - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - if self.n > n { - self.n -= n + 1; - self.iter.nth(n) - } else { - if self.n > 0 { - self.iter.nth(self.n - 1); - self.n = 0; - } - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.n == 0 { - return (0, Some(0)); - } - - let (lower, upper) = self.iter.size_hint(); - - let lower = cmp::min(lower, self.n); - - let upper = match upper { - Some(x) if x < self.n => Some(x), - _ => Some(self.n), - }; - - (lower, upper) - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn check<'a, T, Acc, R: Try>( - n: &'a mut usize, - mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { - move |acc, x| { - *n -= 1; - let r = fold(acc, x); - if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } - } - } - - if self.n == 0 { - try { init } - } else { - let n = &mut self.n; - self.iter.try_fold(init, check(n, fold)).into_try() - } - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Take -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Take {} - -#[stable(feature = "double_ended_take_iterator", since = "1.38.0")] -impl DoubleEndedIterator for Take -where - I: DoubleEndedIterator + ExactSizeIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - if self.n == 0 { - None - } else { - let n = self.n; - self.n -= 1; - self.iter.nth_back(self.iter.len().saturating_sub(n)) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.iter.len(); - if self.n > n { - let m = len.saturating_sub(self.n) + n; - self.n -= n + 1; - self.iter.nth_back(m) - } else { - if len > 0 { - self.iter.nth_back(len - 1); - } - None - } - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - if self.n == 0 { - try { init } - } else { - let len = self.iter.len(); - if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { - try { init } - } else { - self.iter.try_rfold(init, fold) - } - } - } - - #[inline] - fn rfold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.n == 0 { - init - } else { - let len = self.iter.len(); - if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { - init - } else { - self.iter.rfold(init, fold) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Take where I: ExactSizeIterator {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Take where I: FusedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Take {} - -/// An iterator to maintain state while iterating another iterator. -/// -/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`scan`]: Iterator::scan -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Scan { - iter: I, - f: F, - state: St, -} -impl Scan { - pub(super) fn new(iter: I, state: St, f: F) -> Scan { - Scan { iter, state, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Scan { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Scan -where - I: Iterator, - F: FnMut(&mut St, I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - let a = self.iter.next()?; - (self.f)(&mut self.state, a) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the scan function - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn scan<'a, T, St, B, Acc, R: Try>( - state: &'a mut St, - f: &'a mut impl FnMut(&mut St, T) -> Option, - mut fold: impl FnMut(Acc, B) -> R + 'a, - ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { - move |acc, x| match f(state, x) { - None => ControlFlow::Break(try { acc }), - Some(x) => ControlFlow::from_try(fold(acc, x)), - } - } - - let state = &mut self.state; - let f = &mut self.f; - self.iter.try_fold(init, scan(state, f, fold)).into_try() - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Scan -where - I: SourceIter, - F: FnMut(&mut St, I::Item) -> Option, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Scan where - F: FnMut(&mut St, I::Item) -> Option -{ -} - -/// An iterator that calls a function with a reference to each element before -/// yielding it. -/// -/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`inspect`]: Iterator::inspect -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Inspect { - iter: I, - f: F, -} -impl Inspect { - pub(super) fn new(iter: I, f: F) -> Inspect { - Inspect { iter, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Inspect { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Inspect").field("iter", &self.iter).finish() - } -} - -impl Inspect -where - F: FnMut(&I::Item), -{ - #[inline] - fn do_inspect(&mut self, elt: Option) -> Option { - if let Some(ref a) = elt { - (self.f)(a); - } - - elt - } -} - -fn inspect_fold( - mut f: impl FnMut(&T), - mut fold: impl FnMut(Acc, T) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| { - f(&item); - fold(acc, item) - } -} - -fn inspect_try_fold<'a, T, Acc, R>( - f: &'a mut impl FnMut(&T), - mut fold: impl FnMut(Acc, T) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| { - f(&item); - fold(acc, item) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Inspect -where - F: FnMut(&I::Item), -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - let next = self.iter.next(); - self.do_inspect(next) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, inspect_fold(self.f, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Inspect -where - F: FnMut(&I::Item), -{ - #[inline] - fn next_back(&mut self) -> Option { - let next = self.iter.next_back(); - self.do_inspect(next) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, inspect_fold(self.f, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Inspect -where - F: FnMut(&I::Item), -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Inspect where F: FnMut(&I::Item) {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Inspect -where - F: FnMut(&I::Item), - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Inspect where F: FnMut(&I::Item) {} - /// An iterator adapter that produces output as long as the underlying /// iterator produces `Result::Ok` values. /// diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs new file mode 100644 index 00000000000..e7fb3abc942 --- /dev/null +++ b/library/core/src/iter/adapters/peekable.rs @@ -0,0 +1,301 @@ +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::Try; + +/// An iterator with a `peek()` that returns an optional reference to the next +/// element. +/// +/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`peekable`]: Iterator::peekable +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Peekable { + iter: I, + /// Remember a peeked value, even if it was None. + peeked: Option>, +} + +impl Peekable { + pub(in crate::iter) fn new(iter: I) -> Peekable { + Peekable { iter, peeked: None } + } +} + +// Peekable must remember if a None has been seen in the `.peek()` method. +// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the +// underlying iterator at most once. This does not by itself make the iterator +// fused. +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Peekable { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.peeked.take() { + Some(v) => v, + None => self.iter.next(), + } + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn count(mut self) -> usize { + match self.peeked.take() { + Some(None) => 0, + Some(Some(_)) => 1 + self.iter.count(), + None => self.iter.count(), + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + match self.peeked.take() { + Some(None) => None, + Some(v @ Some(_)) if n == 0 => v, + Some(Some(_)) => self.iter.nth(n - 1), + None => self.iter.nth(n), + } + } + + #[inline] + fn last(mut self) -> Option { + let peek_opt = match self.peeked.take() { + Some(None) => return None, + Some(v) => v, + None => None, + }; + self.iter.last().or(peek_opt) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let peek_len = match self.peeked { + Some(None) => return (0, Some(0)), + Some(Some(_)) => 1, + None => 0, + }; + let (lo, hi) = self.iter.size_hint(); + let lo = lo.saturating_add(peek_len); + let hi = match hi { + Some(x) => x.checked_add(peek_len), + None => None, + }; + (lo, hi) + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let acc = match self.peeked.take() { + Some(None) => return try { init }, + Some(Some(v)) => f(init, v)?, + None => init, + }; + self.iter.try_fold(acc, f) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let acc = match self.peeked { + Some(None) => return init, + Some(Some(v)) => fold(init, v), + None => init, + }; + self.iter.fold(acc, fold) + } +} + +#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")] +impl DoubleEndedIterator for Peekable +where + I: DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + match self.peeked.as_mut() { + Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()), + Some(None) => None, + None => self.iter.next_back(), + } + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + match self.peeked.take() { + Some(None) => try { init }, + Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { + Ok(acc) => f(acc, v), + Err(e) => { + self.peeked = Some(Some(v)); + Try::from_error(e) + } + }, + None => self.iter.try_rfold(init, f), + } + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + match self.peeked { + Some(None) => init, + Some(Some(v)) => { + let acc = self.iter.rfold(init, &mut fold); + fold(acc, v) + } + None => self.iter.rfold(init, fold), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Peekable {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Peekable {} + +impl Peekable { + /// Returns a reference to the next() value without advancing the iterator. + /// + /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. + /// But if the iteration is over, `None` is returned. + /// + /// [`next`]: Iterator::next + /// + /// Because `peek()` returns a reference, and many iterators iterate over + /// references, there can be a possibly confusing situation where the + /// return value is a double reference. You can see this effect in the + /// examples below. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let xs = [1, 2, 3]; + /// + /// let mut iter = xs.iter().peekable(); + /// + /// // peek() lets us see into the future + /// assert_eq!(iter.peek(), Some(&&1)); + /// assert_eq!(iter.next(), Some(&1)); + /// + /// assert_eq!(iter.next(), Some(&2)); + /// + /// // The iterator does not advance even if we `peek` multiple times + /// assert_eq!(iter.peek(), Some(&&3)); + /// assert_eq!(iter.peek(), Some(&&3)); + /// + /// assert_eq!(iter.next(), Some(&3)); + /// + /// // After the iterator is finished, so is `peek()` + /// assert_eq!(iter.peek(), None); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn peek(&mut self) -> Option<&I::Item> { + let iter = &mut self.iter; + self.peeked.get_or_insert_with(|| iter.next()).as_ref() + } + + /// Consume and return the next value of this iterator if a condition is true. + /// + /// If `func` returns `true` for the next value of this iterator, consume and return it. + /// Otherwise, return `None`. + /// + /// # Examples + /// Consume a number if it's equal to 0. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (0..5).peekable(); + /// // The first item of the iterator is 0; consume it. + /// assert_eq!(iter.next_if(|&x| x == 0), Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(iter.next_if(|&x| x == 0), None); + /// // `next_if` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(iter.next(), Some(1)); + /// ``` + /// + /// Consume any number less than 10. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (1..20).peekable(); + /// // Consume all numbers less than 10 + /// while iter.next_if(|&x| x < 10).is_some() {} + /// // The next value returned will be 10 + /// assert_eq!(iter.next(), Some(10)); + /// ``` + #[unstable(feature = "peekable_next_if", issue = "72480")] + pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { + match self.next() { + Some(matched) if func(&matched) => Some(matched), + other => { + // Since we called `self.next()`, we consumed `self.peeked`. + assert!(self.peeked.is_none()); + self.peeked = Some(other); + None + } + } + } + + /// Consume and return the next item if it is equal to `expected`. + /// + /// # Example + /// Consume a number if it's equal to 0. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (0..5).peekable(); + /// // The first item of the iterator is 0; consume it. + /// assert_eq!(iter.next_if_eq(&0), Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(iter.next_if_eq(&0), None); + /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(iter.next(), Some(1)); + /// ``` + #[unstable(feature = "peekable_next_if", issue = "72480")] + pub fn next_if_eq(&mut self, expected: &T) -> Option + where + T: ?Sized, + I::Item: PartialEq, + { + self.next_if(|next| next == expected) + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Peekable where I: TrustedLen {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Peekable +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Peekable {} diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs new file mode 100644 index 00000000000..105ed40a3ed --- /dev/null +++ b/library/core/src/iter/adapters/rev.rs @@ -0,0 +1,137 @@ +use crate::iter::{FusedIterator, TrustedLen}; +use crate::ops::Try; + +/// A double-ended iterator with the direction inverted. +/// +/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`rev`]: Iterator::rev +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rev { + iter: T, +} + +impl Rev { + pub(in crate::iter) fn new(iter: T) -> Rev { + Rev { iter } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Rev +where + I: DoubleEndedIterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + self.iter.next_back() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_back_by(n) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<::Item> { + self.iter.nth_back(n) + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, f) + } + + fn fold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, f) + } + + #[inline] + fn find

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.iter.rfind(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Rev +where + I: DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<::Item> { + self.iter.next() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_by(n) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { + self.iter.nth(n) + } + + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, f) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, f) + } + + fn rfind

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.iter.find(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Rev +where + I: ExactSizeIterator + DoubleEndedIterator, +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Rev where I: TrustedLen + DoubleEndedIterator {} diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs new file mode 100644 index 00000000000..0214899295e --- /dev/null +++ b/library/core/src/iter/adapters/scan.rs @@ -0,0 +1,111 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator to maintain state while iterating another iterator. +/// +/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`scan`]: Iterator::scan +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Scan { + iter: I, + f: F, + state: St, +} + +impl Scan { + pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan { + Scan { iter, state, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Scan { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Scan +where + I: Iterator, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + let a = self.iter.next()?; + (self.f)(&mut self.state, a) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the scan function + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn scan<'a, T, St, B, Acc, R: Try>( + state: &'a mut St, + f: &'a mut impl FnMut(&mut St, T) -> Option, + mut fold: impl FnMut(Acc, B) -> R + 'a, + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { + move |acc, x| match f(state, x) { + None => ControlFlow::Break(try { acc }), + Some(x) => ControlFlow::from_try(fold(acc, x)), + } + } + + let state = &mut self.state; + let f = &mut self.f; + self.iter.try_fold(init, scan(state, f, fold)).into_try() + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Scan +where + I: SourceIter, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Scan where + F: FnMut(&mut St, I::Item) -> Option +{ +} diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs new file mode 100644 index 00000000000..dd5325660c3 --- /dev/null +++ b/library/core/src/iter/adapters/skip.rs @@ -0,0 +1,199 @@ +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that skips over `n` elements of `iter`. +/// +/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip`]: Iterator::skip +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Skip { + iter: I, + n: usize, +} + +impl Skip { + pub(in crate::iter) fn new(iter: I, n: usize) -> Skip { + Skip { iter, n } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Skip +where + I: Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.n == 0 { + self.iter.next() + } else { + let old_n = self.n; + self.n = 0; + self.iter.nth(old_n) + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + // Can't just add n + self.n due to overflow. + if self.n > 0 { + let to_skip = self.n; + self.n = 0; + // nth(n) skips n+1 + self.iter.nth(to_skip - 1)?; + } + self.iter.nth(n) + } + + #[inline] + fn count(mut self) -> usize { + if self.n > 0 { + // nth(n) skips n+1 + if self.iter.nth(self.n - 1).is_none() { + return 0; + } + } + self.iter.count() + } + + #[inline] + fn last(mut self) -> Option { + if self.n > 0 { + // nth(n) skips n+1 + self.iter.nth(self.n - 1)?; + } + self.iter.last() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + + let lower = lower.saturating_sub(self.n); + let upper = match upper { + Some(x) => Some(x.saturating_sub(self.n)), + None => None, + }; + + (lower, upper) + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + let n = self.n; + self.n = 0; + if n > 0 { + // nth(n) skips n+1 + if self.iter.nth(n - 1).is_none() { + return try { init }; + } + } + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.n > 0 { + // nth(n) skips n+1 + if self.iter.nth(self.n - 1).is_none() { + return init; + } + } + self.iter.fold(init, fold) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Skip where I: ExactSizeIterator {} + +#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")] +impl DoubleEndedIterator for Skip +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + fn next_back(&mut self) -> Option { + if self.len() > 0 { self.iter.next_back() } else { None } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n < len { + self.iter.nth_back(n) + } else { + if len > 0 { + // consume the original iterator + self.iter.nth_back(len - 1); + } + None + } + } + + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn check>( + mut n: usize, + mut fold: impl FnMut(Acc, T) -> R, + ) -> impl FnMut(Acc, T) -> ControlFlow { + move |acc, x| { + n -= 1; + let r = fold(acc, x); + if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } + } + } + + let n = self.len(); + if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } + } + + fn rfold(mut self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_rfold(init, ok(fold)).unwrap() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Skip where I: FusedIterator {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Skip +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Skip {} diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs new file mode 100644 index 00000000000..efcb469fc95 --- /dev/null +++ b/library/core/src/iter/adapters/skip_while.rs @@ -0,0 +1,126 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::Try; + +/// An iterator that rejects elements while `predicate` returns `true`. +/// +/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip_while`]: Iterator::skip_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct SkipWhile { + iter: I, + flag: bool, + predicate: P, +} + +impl SkipWhile { + pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile { + SkipWhile { iter, flag: false, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SkipWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for SkipWhile +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + fn check<'a, T>( + flag: &'a mut bool, + pred: &'a mut impl FnMut(&T) -> bool, + ) -> impl FnMut(&T) -> bool + 'a { + move |x| { + if *flag || !pred(x) { + *flag = true; + true + } else { + false + } + } + } + + let flag = &mut self.flag; + let pred = &mut self.predicate; + self.iter.find(check(flag, pred)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + if !self.flag { + match self.next() { + Some(v) => init = fold(init, v)?, + None => return try { init }, + } + } + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(mut self, mut init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if !self.flag { + match self.next() { + Some(v) => init = fold(init, v), + None => return init, + } + } + self.iter.fold(init, fold) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SkipWhile +where + I: FusedIterator, + P: FnMut(&I::Item) -> bool, +{ +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for SkipWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for SkipWhile where + F: FnMut(&I::Item) -> bool +{ +} diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs new file mode 100644 index 00000000000..2ba56eeccba --- /dev/null +++ b/library/core/src/iter/adapters/step_by.rs @@ -0,0 +1,235 @@ +use crate::{intrinsics, iter::from_fn, ops::Try}; + +/// An iterator for stepping iterators by a custom amount. +/// +/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See +/// its documentation for more. +/// +/// [`step_by`]: Iterator::step_by +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "iterator_step_by", since = "1.28.0")] +#[derive(Clone, Debug)] +pub struct StepBy { + iter: I, + step: usize, + first_take: bool, +} + +impl StepBy { + pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy { + assert!(step != 0); + StepBy { iter, step: step - 1, first_take: true } + } +} + +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl Iterator for StepBy +where + I: Iterator, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.first_take { + self.first_take = false; + self.iter.next() + } else { + self.iter.nth(self.step) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + #[inline] + fn first_size(step: usize) -> impl Fn(usize) -> usize { + move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } + } + + #[inline] + fn other_size(step: usize) -> impl Fn(usize) -> usize { + move |n| n / (step + 1) + } + + let (low, high) = self.iter.size_hint(); + + if self.first_take { + let f = first_size(self.step); + (f(low), high.map(f)) + } else { + let f = other_size(self.step); + (f(low), high.map(f)) + } + } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option { + if self.first_take { + self.first_take = false; + let first = self.iter.next(); + if n == 0 { + return first; + } + n -= 1; + } + // n and self.step are indices, we need to add 1 to get the amount of elements + // When calling `.nth`, we need to subtract 1 again to convert back to an index + // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` + let mut step = self.step + 1; + // n + 1 could overflow + // thus, if n is usize::MAX, instead of adding one, we call .nth(step) + if n == usize::MAX { + self.iter.nth(step - 1); + } else { + n += 1; + } + + // overflow handling + loop { + let mul = n.checked_mul(step); + { + if intrinsics::likely(mul.is_some()) { + return self.iter.nth(mul.unwrap() - 1); + } + } + let div_n = usize::MAX / n; + let div_step = usize::MAX / step; + let nth_n = div_n * n; + let nth_step = div_step * step; + let nth = if nth_n > nth_step { + step -= div_n; + nth_n + } else { + n -= div_step; + nth_step + }; + self.iter.nth(nth - 1); + } + } + + fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { + move || iter.nth(step) + } + + if self.first_take { + self.first_take = false; + match self.iter.next() { + None => return try { acc }, + Some(x) => acc = f(acc, x)?, + } + } + from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) + } + + fn fold(mut self, mut acc: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { + move || iter.nth(step) + } + + if self.first_take { + self.first_take = false; + match self.iter.next() { + None => return acc, + Some(x) => acc = f(acc, x), + } + } + from_fn(nth(&mut self.iter, self.step)).fold(acc, f) + } +} + +impl StepBy +where + I: ExactSizeIterator, +{ + // The zero-based index starting from the end of the iterator of the + // last element. Used in the `DoubleEndedIterator` implementation. + fn next_back_index(&self) -> usize { + let rem = self.iter.len() % (self.step + 1); + if self.first_take { + if rem == 0 { self.step } else { rem - 1 } + } else { + rem + } + } +} + +#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] +impl DoubleEndedIterator for StepBy +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.nth_back(self.next_back_index()) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + // `self.iter.nth_back(usize::MAX)` does the right thing here when `n` + // is out of bounds because the length of `self.iter` does not exceed + // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is + // zero-indexed + let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index()); + self.iter.nth_back(n) + } + + fn try_rfold(&mut self, init: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn nth_back( + iter: &mut I, + step: usize, + ) -> impl FnMut() -> Option + '_ { + move || iter.nth_back(step) + } + + match self.next_back() { + None => try { init }, + Some(x) => { + let acc = f(init, x)?; + from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) + } + } + } + + #[inline] + fn rfold(mut self, init: Acc, mut f: F) -> Acc + where + Self: Sized, + F: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn nth_back( + iter: &mut I, + step: usize, + ) -> impl FnMut() -> Option + '_ { + move || iter.nth_back(step) + } + + match self.next_back() { + None => init, + Some(x) => { + let acc = f(init, x); + from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f) + } + } + } +} + +// StepBy can only make the iterator shorter, so the len will still fit. +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs new file mode 100644 index 00000000000..9efc7a480ae --- /dev/null +++ b/library/core/src/iter/adapters/take.rs @@ -0,0 +1,209 @@ +use crate::cmp; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that only iterates over the first `n` iterations of `iter`. +/// +/// This `struct` is created by the [`take`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take`]: Iterator::take +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Take { + iter: I, + n: usize, +} + +impl Take { + pub(in crate::iter) fn new(iter: I, n: usize) -> Take { + Take { iter, n } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Take +where + I: Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + if self.n != 0 { + self.n -= 1; + self.iter.next() + } else { + None + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.n > n { + self.n -= n + 1; + self.iter.nth(n) + } else { + if self.n > 0 { + self.iter.nth(self.n - 1); + self.n = 0; + } + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.n == 0 { + return (0, Some(0)); + } + + let (lower, upper) = self.iter.size_hint(); + + let lower = cmp::min(lower, self.n); + + let upper = match upper { + Some(x) if x < self.n => Some(x), + _ => Some(self.n), + }; + + (lower, upper) + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn check<'a, T, Acc, R: Try>( + n: &'a mut usize, + mut fold: impl FnMut(Acc, T) -> R + 'a, + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { + move |acc, x| { + *n -= 1; + let r = fold(acc, x); + if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } + } + } + + if self.n == 0 { + try { init } + } else { + let n = &mut self.n; + self.iter.try_fold(init, check(n, fold)).into_try() + } + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Take +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Take {} + +#[stable(feature = "double_ended_take_iterator", since = "1.38.0")] +impl DoubleEndedIterator for Take +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.n == 0 { + None + } else { + let n = self.n; + self.n -= 1; + self.iter.nth_back(self.iter.len().saturating_sub(n)) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.iter.len(); + if self.n > n { + let m = len.saturating_sub(self.n) + n; + self.n -= n + 1; + self.iter.nth_back(m) + } else { + if len > 0 { + self.iter.nth_back(len - 1); + } + None + } + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + if self.n == 0 { + try { init } + } else { + let len = self.iter.len(); + if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { + try { init } + } else { + self.iter.try_rfold(init, fold) + } + } + } + + #[inline] + fn rfold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.n == 0 { + init + } else { + let len = self.iter.len(); + if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { + init + } else { + self.iter.rfold(init, fold) + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Take where I: ExactSizeIterator {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Take where I: FusedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Take {} diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs new file mode 100644 index 00000000000..746eb41f4c3 --- /dev/null +++ b/library/core/src/iter/adapters/take_while.rs @@ -0,0 +1,139 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that only accepts elements while `predicate` returns `true`. +/// +/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take_while`]: Iterator::take_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct TakeWhile { + iter: I, + flag: bool, + predicate: P, +} + +impl TakeWhile { + pub(in crate::iter) fn new(iter: I, predicate: P) -> TakeWhile { + TakeWhile { iter, flag: false, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for TakeWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for TakeWhile +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.flag { + None + } else { + let x = self.iter.next()?; + if (self.predicate)(&x) { + Some(x) + } else { + self.flag = true; + None + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.flag { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn check<'a, T, Acc, R: Try>( + flag: &'a mut bool, + p: &'a mut impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> R + 'a, + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { + move |acc, x| { + if p(&x) { + ControlFlow::from_try(fold(acc, x)) + } else { + *flag = true; + ControlFlow::Break(try { acc }) + } + } + } + + if self.flag { + try { init } + } else { + let flag = &mut self.flag; + let p = &mut self.predicate; + self.iter.try_fold(init, check(flag, p, fold)).into_try() + } + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for TakeWhile +where + I: FusedIterator, + P: FnMut(&I::Item) -> bool, +{ +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for TakeWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for TakeWhile where + F: FnMut(&I::Item) -> bool +{ +} diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 78712988eae..8cd4c775231 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,10 +1,7 @@ use crate::cmp; use crate::fmt::{self, Debug}; - -use super::super::{ - DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, SourceIter, - TrustedLen, -}; +use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; +use crate::iter::{InPlaceIterable, SourceIter, TrustedLen}; /// An iterator that iterates two other iterators simultaneously. /// @@ -21,7 +18,7 @@ pub struct Zip { len: usize, } impl Zip { - pub(in super::super) fn new(a: A, b: B) -> Zip { + pub(in crate::iter) fn new(a: A, b: B) -> Zip { ZipImpl::new(a, b) } fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 59f333e888b..072373c00f6 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -335,15 +335,14 @@ #[stable(feature = "fused", since = "1.26.0")] pub use self::traits::FusedIterator; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::traits::InPlaceIterable; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::traits::{DoubleEndedIterator, Extend, FromIterator, IntoIterator}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::traits::{ExactSizeIterator, Product, Sum}; - -#[unstable(issue = "none", feature = "inplace_iteration")] -pub use self::traits::InPlaceIterable; +pub use self::traits::{ + DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, +}; #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::adapters::Cloned; @@ -351,21 +350,19 @@ pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; - #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; -#[unstable(issue = "none", feature = "inplace_iteration")] +#[unstable(feature = "inplace_iteration", issue = "none")] pub use self::adapters::SourceIter; #[stable(feature = "iterator_step_by", since = "1.28.0")] pub use self::adapters::StepBy; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccess; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::adapters::{Chain, Cycle, Enumerate, Filter, FilterMap, Map, Rev, Zip}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::adapters::{FlatMap, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::adapters::{Fuse, Inspect}; +pub use self::adapters::{ + Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, + Skip, SkipWhile, Take, TakeWhile, Zip, +}; pub(crate) use self::adapters::process_results; diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 44da8f4715c..de0663141e2 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -1,625 +1,27 @@ -use crate::fmt; -use crate::marker; +mod empty; +mod from_fn; +mod once; +mod once_with; +mod repeat; +mod repeat_with; +mod successors; -use super::{FusedIterator, TrustedLen}; +pub use self::repeat::{repeat, Repeat}; -/// An iterator that repeats an element endlessly. -/// -/// This `struct` is created by the [`repeat()`] function. See its documentation for more. -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Repeat { - element: A, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Repeat { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - Some(self.element.clone()) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Repeat { - #[inline] - fn next_back(&mut self) -> Option { - Some(self.element.clone()) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Repeat {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Repeat {} - -/// Creates a new iterator that endlessly repeats a single element. -/// -/// The `repeat()` function repeats a single value over and over again. -/// -/// Infinite iterators like `repeat()` are often used with adapters like -/// [`Iterator::take()`], in order to make them finite. -/// -/// If the element type of the iterator you need does not implement `Clone`, -/// or if you do not want to keep the repeated element in memory, you can -/// instead use the [`repeat_with()`] function. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // the number four 4ever: -/// let mut fours = iter::repeat(4); -/// -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// -/// // yup, still four -/// assert_eq!(Some(4), fours.next()); -/// ``` -/// -/// Going finite with [`Iterator::take()`]: -/// -/// ``` -/// use std::iter; -/// -/// // that last example was too many fours. Let's only have four fours. -/// let mut four_fours = iter::repeat(4).take(4); -/// -/// assert_eq!(Some(4), four_fours.next()); -/// assert_eq!(Some(4), four_fours.next()); -/// assert_eq!(Some(4), four_fours.next()); -/// assert_eq!(Some(4), four_fours.next()); -/// -/// // ... and now we're done -/// assert_eq!(None, four_fours.next()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn repeat(elt: T) -> Repeat { - Repeat { element: elt } -} - -/// An iterator that repeats elements of type `A` endlessly by -/// applying the provided closure `F: FnMut() -> A`. -/// -/// This `struct` is created by the [`repeat_with()`] function. -/// See its documentation for more. -#[derive(Copy, Clone, Debug)] -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -pub struct RepeatWith { - repeater: F, -} - -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -impl A> Iterator for RepeatWith { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - Some((self.repeater)()) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -impl A> FusedIterator for RepeatWith {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl A> TrustedLen for RepeatWith {} - -/// Creates a new iterator that repeats elements of type `A` endlessly by -/// applying the provided closure, the repeater, `F: FnMut() -> A`. -/// -/// The `repeat_with()` function calls the repeater over and over again. -/// -/// Infinite iterators like `repeat_with()` are often used with adapters like -/// [`Iterator::take()`], in order to make them finite. -/// -/// If the element type of the iterator you need implements [`Clone`], and -/// it is OK to keep the source element in memory, you should instead use -/// the [`repeat()`] function. -/// -/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. -/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], -/// please open a GitHub issue explaining your use case. -/// -/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // let's assume we have some value of a type that is not `Clone` -/// // or which don't want to have in memory just yet because it is expensive: -/// #[derive(PartialEq, Debug)] -/// struct Expensive; -/// -/// // a particular value forever: -/// let mut things = iter::repeat_with(|| Expensive); -/// -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// ``` -/// -/// Using mutation and going finite: -/// -/// ```rust -/// use std::iter; -/// -/// // From the zeroth to the third power of two: -/// let mut curr = 1; -/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) -/// .take(4); -/// -/// assert_eq!(Some(1), pow2.next()); -/// assert_eq!(Some(2), pow2.next()); -/// assert_eq!(Some(4), pow2.next()); -/// assert_eq!(Some(8), pow2.next()); -/// -/// // ... and now we're done -/// assert_eq!(None, pow2.next()); -/// ``` -#[inline] -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -pub fn repeat_with A>(repeater: F) -> RepeatWith { - RepeatWith { repeater } -} - -/// An iterator that yields nothing. -/// -/// This `struct` is created by the [`empty()`] function. See its documentation for more. #[stable(feature = "iter_empty", since = "1.2.0")] -pub struct Empty(marker::PhantomData); - -#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] -unsafe impl Send for Empty {} -#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] -unsafe impl Sync for Empty {} +pub use self::empty::{empty, Empty}; -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Empty { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Empty") - } -} - -#[stable(feature = "iter_empty", since = "1.2.0")] -impl Iterator for Empty { - type Item = T; - - fn next(&mut self) -> Option { - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -#[stable(feature = "iter_empty", since = "1.2.0")] -impl DoubleEndedIterator for Empty { - fn next_back(&mut self) -> Option { - None - } -} - -#[stable(feature = "iter_empty", since = "1.2.0")] -impl ExactSizeIterator for Empty { - fn len(&self) -> usize { - 0 - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Empty {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Empty {} - -// not #[derive] because that adds a Clone bound on T, -// which isn't necessary. -#[stable(feature = "iter_empty", since = "1.2.0")] -impl Clone for Empty { - fn clone(&self) -> Empty { - Empty(marker::PhantomData) - } -} - -// not #[derive] because that adds a Default bound on T, -// which isn't necessary. -#[stable(feature = "iter_empty", since = "1.2.0")] -impl Default for Empty { - fn default() -> Empty { - Empty(marker::PhantomData) - } -} - -/// Creates an iterator that yields nothing. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // this could have been an iterator over i32, but alas, it's just not. -/// let mut nope = iter::empty::(); -/// -/// assert_eq!(None, nope.next()); -/// ``` -#[stable(feature = "iter_empty", since = "1.2.0")] -#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")] -pub const fn empty() -> Empty { - Empty(marker::PhantomData) -} - -/// An iterator that yields an element exactly once. -/// -/// This `struct` is created by the [`once()`] function. See its documentation for more. -#[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] -pub struct Once { - inner: crate::option::IntoIter, -} +pub use self::once::{once, Once}; -#[stable(feature = "iter_once", since = "1.2.0")] -impl Iterator for Once { - type Item = T; - - fn next(&mut self) -> Option { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "iter_once", since = "1.2.0")] -impl DoubleEndedIterator for Once { - fn next_back(&mut self) -> Option { - self.inner.next_back() - } -} - -#[stable(feature = "iter_once", since = "1.2.0")] -impl ExactSizeIterator for Once { - fn len(&self) -> usize { - self.inner.len() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Once {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Once {} - -/// Creates an iterator that yields an element exactly once. -/// -/// This is commonly used to adapt a single value into a [`chain()`] of other -/// kinds of iteration. Maybe you have an iterator that covers almost -/// everything, but you need an extra special case. Maybe you have a function -/// which works on iterators, but you only need to process one value. -/// -/// [`chain()`]: Iterator::chain -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // one is the loneliest number -/// let mut one = iter::once(1); -/// -/// assert_eq!(Some(1), one.next()); -/// -/// // just one, that's all we get -/// assert_eq!(None, one.next()); -/// ``` -/// -/// Chaining together with another iterator. Let's say that we want to iterate -/// over each file of the `.foo` directory, but also a configuration file, -/// `.foorc`: -/// -/// ```no_run -/// use std::iter; -/// use std::fs; -/// use std::path::PathBuf; -/// -/// let dirs = fs::read_dir(".foo").unwrap(); -/// -/// // we need to convert from an iterator of DirEntry-s to an iterator of -/// // PathBufs, so we use map -/// let dirs = dirs.map(|file| file.unwrap().path()); -/// -/// // now, our iterator just for our config file -/// let config = iter::once(PathBuf::from(".foorc")); -/// -/// // chain the two iterators together into one big iterator -/// let files = dirs.chain(config); -/// -/// // this will give us all of the files in .foo as well as .foorc -/// for f in files { -/// println!("{:?}", f); -/// } -/// ``` -#[stable(feature = "iter_once", since = "1.2.0")] -pub fn once(value: T) -> Once { - Once { inner: Some(value).into_iter() } -} - -/// An iterator that yields a single element of type `A` by -/// applying the provided closure `F: FnOnce() -> A`. -/// -/// This `struct` is created by the [`once_with()`] function. -/// See its documentation for more. -#[derive(Clone, Debug)] -#[stable(feature = "iter_once_with", since = "1.43.0")] -pub struct OnceWith { - gen: Option, -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> Iterator for OnceWith { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - let f = self.gen.take()?; - Some(f()) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.gen.iter().size_hint() - } -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> DoubleEndedIterator for OnceWith { - fn next_back(&mut self) -> Option { - self.next() - } -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> ExactSizeIterator for OnceWith { - fn len(&self) -> usize { - self.gen.iter().len() - } -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> FusedIterator for OnceWith {} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -unsafe impl A> TrustedLen for OnceWith {} - -/// Creates an iterator that lazily generates a value exactly once by invoking -/// the provided closure. -/// -/// This is commonly used to adapt a single value generator into a [`chain()`] of -/// other kinds of iteration. Maybe you have an iterator that covers almost -/// everything, but you need an extra special case. Maybe you have a function -/// which works on iterators, but you only need to process one value. -/// -/// Unlike [`once()`], this function will lazily generate the value on request. -/// -/// [`chain()`]: Iterator::chain -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // one is the loneliest number -/// let mut one = iter::once_with(|| 1); -/// -/// assert_eq!(Some(1), one.next()); -/// -/// // just one, that's all we get -/// assert_eq!(None, one.next()); -/// ``` -/// -/// Chaining together with another iterator. Let's say that we want to iterate -/// over each file of the `.foo` directory, but also a configuration file, -/// `.foorc`: -/// -/// ```no_run -/// use std::iter; -/// use std::fs; -/// use std::path::PathBuf; -/// -/// let dirs = fs::read_dir(".foo").unwrap(); -/// -/// // we need to convert from an iterator of DirEntry-s to an iterator of -/// // PathBufs, so we use map -/// let dirs = dirs.map(|file| file.unwrap().path()); -/// -/// // now, our iterator just for our config file -/// let config = iter::once_with(|| PathBuf::from(".foorc")); -/// -/// // chain the two iterators together into one big iterator -/// let files = dirs.chain(config); -/// -/// // this will give us all of the files in .foo as well as .foorc -/// for f in files { -/// println!("{:?}", f); -/// } -/// ``` -#[inline] -#[stable(feature = "iter_once_with", since = "1.43.0")] -pub fn once_with A>(gen: F) -> OnceWith { - OnceWith { gen: Some(gen) } -} - -/// Creates a new iterator where each iteration calls the provided closure -/// `F: FnMut() -> Option`. -/// -/// This allows creating a custom iterator with any behavior -/// without using the more verbose syntax of creating a dedicated type -/// and implementing the [`Iterator`] trait for it. -/// -/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, -/// and therefore conservatively does not implement [`FusedIterator`], -/// or override [`Iterator::size_hint()`] from its default `(0, None)`. -/// -/// The closure can use captures and its environment to track state across iterations. Depending on -/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. -/// -/// [`move`]: ../../std/keyword.move.html -/// -/// # Examples -/// -/// Let’s re-implement the counter iterator from the [module-level documentation]: -/// -/// [module-level documentation]: super -/// -/// ``` -/// let mut count = 0; -/// let counter = std::iter::from_fn(move || { -/// // Increment our count. This is why we started at zero. -/// count += 1; -/// -/// // Check to see if we've finished counting or not. -/// if count < 6 { -/// Some(count) -/// } else { -/// None -/// } -/// }); -/// assert_eq!(counter.collect::>(), &[1, 2, 3, 4, 5]); -/// ``` -#[inline] -#[stable(feature = "iter_from_fn", since = "1.34.0")] -pub fn from_fn(f: F) -> FromFn -where - F: FnMut() -> Option, -{ - FromFn(f) -} - -/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. -/// -/// This `struct` is created by the [`iter::from_fn()`] function. -/// See its documentation for more. -/// -/// [`iter::from_fn()`]: from_fn -#[derive(Clone)] -#[stable(feature = "iter_from_fn", since = "1.34.0")] -pub struct FromFn(F); - -#[stable(feature = "iter_from_fn", since = "1.34.0")] -impl Iterator for FromFn -where - F: FnMut() -> Option, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - (self.0)() - } -} +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +pub use self::repeat_with::{repeat_with, RepeatWith}; #[stable(feature = "iter_from_fn", since = "1.34.0")] -impl fmt::Debug for FromFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FromFn").finish() - } -} +pub use self::from_fn::{from_fn, FromFn}; -/// Creates a new iterator where each successive item is computed based on the preceding one. -/// -/// The iterator starts with the given first item (if any) -/// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. -/// -/// ``` -/// use std::iter::successors; -/// -/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); -/// assert_eq!(powers_of_10.collect::>(), &[1, 10, 100, 1_000, 10_000]); -/// ``` #[stable(feature = "iter_successors", since = "1.34.0")] -pub fn successors(first: Option, succ: F) -> Successors -where - F: FnMut(&T) -> Option, -{ - // If this function returned `impl Iterator` - // it could be based on `unfold` and not need a dedicated type. - // However having a named `Successors` type allows it to be `Clone` when `T` and `F` are. - Successors { next: first, succ } -} +pub use self::successors::{successors, Successors}; -/// An new iterator where each successive item is computed based on the preceding one. -/// -/// This `struct` is created by the [`iter::successors()`] function. -/// See its documentation for more. -/// -/// [`iter::successors()`]: successors -#[derive(Clone)] -#[stable(feature = "iter_successors", since = "1.34.0")] -pub struct Successors { - next: Option, - succ: F, -} - -#[stable(feature = "iter_successors", since = "1.34.0")] -impl Iterator for Successors -where - F: FnMut(&T) -> Option, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - let item = self.next.take()?; - self.next = (self.succ)(&item); - Some(item) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.next.is_some() { (1, None) } else { (0, Some(0)) } - } -} - -#[stable(feature = "iter_successors", since = "1.34.0")] -impl FusedIterator for Successors where F: FnMut(&T) -> Option {} - -#[stable(feature = "iter_successors", since = "1.34.0")] -impl fmt::Debug for Successors { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Successors").field("next", &self.next).finish() - } -} +#[stable(feature = "iter_once_with", since = "1.43.0")] +pub use self::once_with::{once_with, OnceWith}; diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs new file mode 100644 index 00000000000..5d4a9fe8c6c --- /dev/null +++ b/library/core/src/iter/sources/empty.rs @@ -0,0 +1,92 @@ +use crate::fmt; +use crate::iter::{FusedIterator, TrustedLen}; +use crate::marker; + +/// Creates an iterator that yields nothing. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // this could have been an iterator over i32, but alas, it's just not. +/// let mut nope = iter::empty::(); +/// +/// assert_eq!(None, nope.next()); +/// ``` +#[stable(feature = "iter_empty", since = "1.2.0")] +#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")] +pub const fn empty() -> Empty { + Empty(marker::PhantomData) +} + +/// An iterator that yields nothing. +/// +/// This `struct` is created by the [`empty()`] function. See its documentation for more. +#[stable(feature = "iter_empty", since = "1.2.0")] +pub struct Empty(marker::PhantomData); + +#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] +unsafe impl Send for Empty {} +#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] +unsafe impl Sync for Empty {} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Empty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Empty") + } +} + +#[stable(feature = "iter_empty", since = "1.2.0")] +impl Iterator for Empty { + type Item = T; + + fn next(&mut self) -> Option { + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +#[stable(feature = "iter_empty", since = "1.2.0")] +impl DoubleEndedIterator for Empty { + fn next_back(&mut self) -> Option { + None + } +} + +#[stable(feature = "iter_empty", since = "1.2.0")] +impl ExactSizeIterator for Empty { + fn len(&self) -> usize { + 0 + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Empty {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Empty {} + +// not #[derive] because that adds a Clone bound on T, +// which isn't necessary. +#[stable(feature = "iter_empty", since = "1.2.0")] +impl Clone for Empty { + fn clone(&self) -> Empty { + Empty(marker::PhantomData) + } +} + +// not #[derive] because that adds a Default bound on T, +// which isn't necessary. +#[stable(feature = "iter_empty", since = "1.2.0")] +impl Default for Empty { + fn default() -> Empty { + Empty(marker::PhantomData) + } +} diff --git a/library/core/src/iter/sources/from_fn.rs b/library/core/src/iter/sources/from_fn.rs new file mode 100644 index 00000000000..3cd3830471c --- /dev/null +++ b/library/core/src/iter/sources/from_fn.rs @@ -0,0 +1,78 @@ +use crate::fmt; + +/// Creates a new iterator where each iteration calls the provided closure +/// `F: FnMut() -> Option`. +/// +/// This allows creating a custom iterator with any behavior +/// without using the more verbose syntax of creating a dedicated type +/// and implementing the [`Iterator`] trait for it. +/// +/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, +/// and therefore conservatively does not implement [`FusedIterator`], +/// or override [`Iterator::size_hint()`] from its default `(0, None)`. +/// +/// The closure can use captures and its environment to track state across iterations. Depending on +/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. +/// +/// [`move`]: ../../std/keyword.move.html +/// [`FusedIterator`]: crate::iter::FusedIterator +/// +/// # Examples +/// +/// Let’s re-implement the counter iterator from [module-level documentation]: +/// +/// [module-level documentation]: crate::iter +/// +/// ``` +/// let mut count = 0; +/// let counter = std::iter::from_fn(move || { +/// // Increment our count. This is why we started at zero. +/// count += 1; +/// +/// // Check to see if we've finished counting or not. +/// if count < 6 { +/// Some(count) +/// } else { +/// None +/// } +/// }); +/// assert_eq!(counter.collect::>(), &[1, 2, 3, 4, 5]); +/// ``` +#[inline] +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub fn from_fn(f: F) -> FromFn +where + F: FnMut() -> Option, +{ + FromFn(f) +} + +/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. +/// +/// This `struct` is created by the [`iter::from_fn()`] function. +/// See its documentation for more. +/// +/// [`iter::from_fn()`]: from_fn +#[derive(Clone)] +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub struct FromFn(F); + +#[stable(feature = "iter_from_fn", since = "1.34.0")] +impl Iterator for FromFn +where + F: FnMut() -> Option, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + (self.0)() + } +} + +#[stable(feature = "iter_from_fn", since = "1.34.0")] +impl fmt::Debug for FromFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FromFn").finish() + } +} diff --git a/library/core/src/iter/sources/once.rs b/library/core/src/iter/sources/once.rs new file mode 100644 index 00000000000..27bc3dcfd79 --- /dev/null +++ b/library/core/src/iter/sources/once.rs @@ -0,0 +1,99 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates an iterator that yields an element exactly once. +/// +/// This is commonly used to adapt a single value into a [`chain()`] of other +/// kinds of iteration. Maybe you have an iterator that covers almost +/// everything, but you need an extra special case. Maybe you have a function +/// which works on iterators, but you only need to process one value. +/// +/// [`chain()`]: Iterator::chain +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // one is the loneliest number +/// let mut one = iter::once(1); +/// +/// assert_eq!(Some(1), one.next()); +/// +/// // just one, that's all we get +/// assert_eq!(None, one.next()); +/// ``` +/// +/// Chaining together with another iterator. Let's say that we want to iterate +/// over each file of the `.foo` directory, but also a configuration file, +/// `.foorc`: +/// +/// ```no_run +/// use std::iter; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// let dirs = fs::read_dir(".foo").unwrap(); +/// +/// // we need to convert from an iterator of DirEntry-s to an iterator of +/// // PathBufs, so we use map +/// let dirs = dirs.map(|file| file.unwrap().path()); +/// +/// // now, our iterator just for our config file +/// let config = iter::once(PathBuf::from(".foorc")); +/// +/// // chain the two iterators together into one big iterator +/// let files = dirs.chain(config); +/// +/// // this will give us all of the files in .foo as well as .foorc +/// for f in files { +/// println!("{:?}", f); +/// } +/// ``` +#[stable(feature = "iter_once", since = "1.2.0")] +pub fn once(value: T) -> Once { + Once { inner: Some(value).into_iter() } +} + +/// An iterator that yields an element exactly once. +/// +/// This `struct` is created by the [`once()`] function. See its documentation for more. +#[derive(Clone, Debug)] +#[stable(feature = "iter_once", since = "1.2.0")] +pub struct Once { + inner: crate::option::IntoIter, +} + +#[stable(feature = "iter_once", since = "1.2.0")] +impl Iterator for Once { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "iter_once", since = "1.2.0")] +impl DoubleEndedIterator for Once { + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} + +#[stable(feature = "iter_once", since = "1.2.0")] +impl ExactSizeIterator for Once { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Once {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Once {} diff --git a/library/core/src/iter/sources/once_with.rs b/library/core/src/iter/sources/once_with.rs new file mode 100644 index 00000000000..cf6a3c11524 --- /dev/null +++ b/library/core/src/iter/sources/once_with.rs @@ -0,0 +1,109 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates an iterator that lazily generates a value exactly once by invoking +/// the provided closure. +/// +/// This is commonly used to adapt a single value generator into a [`chain()`] of +/// other kinds of iteration. Maybe you have an iterator that covers almost +/// everything, but you need an extra special case. Maybe you have a function +/// which works on iterators, but you only need to process one value. +/// +/// Unlike [`once()`], this function will lazily generate the value on request. +/// +/// [`chain()`]: Iterator::chain +/// [`once()`]: crate::iter::once +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // one is the loneliest number +/// let mut one = iter::once_with(|| 1); +/// +/// assert_eq!(Some(1), one.next()); +/// +/// // just one, that's all we get +/// assert_eq!(None, one.next()); +/// ``` +/// +/// Chaining together with another iterator. Let's say that we want to iterate +/// over each file of the `.foo` directory, but also a configuration file, +/// `.foorc`: +/// +/// ```no_run +/// use std::iter; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// let dirs = fs::read_dir(".foo").unwrap(); +/// +/// // we need to convert from an iterator of DirEntry-s to an iterator of +/// // PathBufs, so we use map +/// let dirs = dirs.map(|file| file.unwrap().path()); +/// +/// // now, our iterator just for our config file +/// let config = iter::once_with(|| PathBuf::from(".foorc")); +/// +/// // chain the two iterators together into one big iterator +/// let files = dirs.chain(config); +/// +/// // this will give us all of the files in .foo as well as .foorc +/// for f in files { +/// println!("{:?}", f); +/// } +/// ``` +#[inline] +#[stable(feature = "iter_once_with", since = "1.43.0")] +pub fn once_with A>(gen: F) -> OnceWith { + OnceWith { gen: Some(gen) } +} + +/// An iterator that yields a single element of type `A` by +/// applying the provided closure `F: FnOnce() -> A`. +/// +/// This `struct` is created by the [`once_with()`] function. +/// See its documentation for more. +#[derive(Clone, Debug)] +#[stable(feature = "iter_once_with", since = "1.43.0")] +pub struct OnceWith { + gen: Option, +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> Iterator for OnceWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + let f = self.gen.take()?; + Some(f()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.gen.iter().size_hint() + } +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> DoubleEndedIterator for OnceWith { + fn next_back(&mut self) -> Option { + self.next() + } +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> ExactSizeIterator for OnceWith { + fn len(&self) -> usize { + self.gen.iter().len() + } +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> FusedIterator for OnceWith {} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +unsafe impl A> TrustedLen for OnceWith {} diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs new file mode 100644 index 00000000000..d1f2879235f --- /dev/null +++ b/library/core/src/iter/sources/repeat.rs @@ -0,0 +1,93 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates a new iterator that endlessly repeats a single element. +/// +/// The `repeat()` function repeats a single value over and over again. +/// +/// Infinite iterators like `repeat()` are often used with adapters like +/// [`Iterator::take()`], in order to make them finite. +/// +/// If the element type of the iterator you need does not implement `Clone`, +/// or if you do not want to keep the repeated element in memory, you can +/// instead use the [`repeat_with()`] function. +/// +/// [`repeat_with()`]: crate::iter::repeat_with +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // the number four 4ever: +/// let mut fours = iter::repeat(4); +/// +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// +/// // yup, still four +/// assert_eq!(Some(4), fours.next()); +/// ``` +/// +/// Going finite with [`Iterator::take()`]: +/// +/// ``` +/// use std::iter; +/// +/// // that last example was too many fours. Let's only have four fours. +/// let mut four_fours = iter::repeat(4).take(4); +/// +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, four_fours.next()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn repeat(elt: T) -> Repeat { + Repeat { element: elt } +} + +/// An iterator that repeats an element endlessly. +/// +/// This `struct` is created by the [`repeat()`] function. See its documentation for more. +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Repeat { + element: A, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Repeat { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + Some(self.element.clone()) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Repeat { + #[inline] + fn next_back(&mut self) -> Option { + Some(self.element.clone()) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Repeat {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Repeat {} diff --git a/library/core/src/iter/sources/repeat_with.rs b/library/core/src/iter/sources/repeat_with.rs new file mode 100644 index 00000000000..44bc6890c55 --- /dev/null +++ b/library/core/src/iter/sources/repeat_with.rs @@ -0,0 +1,98 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates a new iterator that repeats elements of type `A` endlessly by +/// applying the provided closure, the repeater, `F: FnMut() -> A`. +/// +/// The `repeat_with()` function calls the repeater over and over again. +/// +/// Infinite iterators like `repeat_with()` are often used with adapters like +/// [`Iterator::take()`], in order to make them finite. +/// +/// If the element type of the iterator you need implements [`Clone`], and +/// it is OK to keep the source element in memory, you should instead use +/// the [`repeat()`] function. +/// +/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. +/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], +/// please open a GitHub issue explaining your use case. +/// +/// [`repeat()`]: crate::iter::repeat +/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // let's assume we have some value of a type that is not `Clone` +/// // or which don't want to have in memory just yet because it is expensive: +/// #[derive(PartialEq, Debug)] +/// struct Expensive; +/// +/// // a particular value forever: +/// let mut things = iter::repeat_with(|| Expensive); +/// +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// ``` +/// +/// Using mutation and going finite: +/// +/// ```rust +/// use std::iter; +/// +/// // From the zeroth to the third power of two: +/// let mut curr = 1; +/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) +/// .take(4); +/// +/// assert_eq!(Some(1), pow2.next()); +/// assert_eq!(Some(2), pow2.next()); +/// assert_eq!(Some(4), pow2.next()); +/// assert_eq!(Some(8), pow2.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, pow2.next()); +/// ``` +#[inline] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + RepeatWith { repeater } +} + +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`repeat_with()`] function. +/// See its documentation for more. +#[derive(Copy, Clone, Debug)] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +pub struct RepeatWith { + repeater: F, +} + +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + Some((self.repeater)()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} + +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} diff --git a/library/core/src/iter/sources/successors.rs b/library/core/src/iter/sources/successors.rs new file mode 100644 index 00000000000..99f058a901a --- /dev/null +++ b/library/core/src/iter/sources/successors.rs @@ -0,0 +1,66 @@ +use crate::{fmt, iter::FusedIterator}; + +/// Creates a new iterator where each successive item is computed based on the preceding one. +/// +/// The iterator starts with the given first item (if any) +/// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. +/// +/// ``` +/// use std::iter::successors; +/// +/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); +/// assert_eq!(powers_of_10.collect::>(), &[1, 10, 100, 1_000, 10_000]); +/// ``` +#[stable(feature = "iter_successors", since = "1.34.0")] +pub fn successors(first: Option, succ: F) -> Successors +where + F: FnMut(&T) -> Option, +{ + // If this function returned `impl Iterator` + // it could be based on `unfold` and not need a dedicated type. + // However having a named `Successors` type allows it to be `Clone` when `T` and `F` are. + Successors { next: first, succ } +} + +/// An new iterator where each successive item is computed based on the preceding one. +/// +/// This `struct` is created by the [`iter::successors()`] function. +/// See its documentation for more. +/// +/// [`iter::successors()`]: successors +#[derive(Clone)] +#[stable(feature = "iter_successors", since = "1.34.0")] +pub struct Successors { + next: Option, + succ: F, +} + +#[stable(feature = "iter_successors", since = "1.34.0")] +impl Iterator for Successors +where + F: FnMut(&T) -> Option, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + let item = self.next.take()?; + self.next = (self.succ)(&item); + Some(item) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.next.is_some() { (1, None) } else { (0, Some(0)) } + } +} + +#[stable(feature = "iter_successors", since = "1.34.0")] +impl FusedIterator for Successors where F: FnMut(&T) -> Option {} + +#[stable(feature = "iter_successors", since = "1.34.0")] +impl fmt::Debug for Successors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Successors").field("next", &self.next).finish() + } +} diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index cdf742057b7..29364d0ce9b 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -156,18 +156,18 @@ pub trait StructuralPartialEq { /// Required trait for constants used in pattern matches. /// /// Any type that derives `Eq` automatically implements this trait, *regardless* -/// of whether its type-parameters implement `Eq`. +/// of whether its type parameters implement `Eq`. /// -/// This is a hack to workaround a limitation in our type-system. +/// This is a hack to work around a limitation in our type system. /// -/// Background: +/// # Background /// /// We want to require that types of consts used in pattern matches /// have the attribute `#[derive(PartialEq, Eq)]`. /// /// In a more ideal world, we could check that requirement by just checking that -/// the given type implements both (1.) the `StructuralPartialEq` trait *and* -/// (2.) the `Eq` trait. However, you can have ADTs that *do* `derive(PartialEq, Eq)`, +/// the given type implements both the `StructuralPartialEq` trait *and* +/// the `Eq` trait. However, you can have ADTs that *do* `derive(PartialEq, Eq)`, /// and be a case that we want the compiler to accept, and yet the constant's /// type fails to implement `Eq`. /// @@ -176,8 +176,11 @@ pub trait StructuralPartialEq { /// ```rust /// #[derive(PartialEq, Eq)] /// struct Wrap(X); +/// /// fn higher_order(_: &()) { } +/// /// const CFN: Wrap = Wrap(higher_order); +/// /// fn main() { /// match CFN { /// CFN => {} diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 660b7db70be..94ac16954a7 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -392,7 +392,7 @@ pub fn write(&mut self, val: T) -> &mut T { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); } /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. /// let x_vec = unsafe { &*x.as_ptr() }; /// assert_eq!(x_vec.len(), 3); @@ -429,7 +429,7 @@ pub const fn as_ptr(&self) -> *const T { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); } /// // Create a reference into the `MaybeUninit>`. /// // This is okay because we initialized it. /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; @@ -565,7 +565,7 @@ pub unsafe fn assume_init(self) -> T { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>>::uninit(); - /// x.write(Some(vec![0,1,2])); + /// x.write(Some(vec![0, 1, 2])); /// let x1 = unsafe { x.assume_init_read() }; /// let x2 = unsafe { x.assume_init_read() }; /// // We now created two copies of the same vector, leading to a double-free ⚠️ when diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 86e6352d132..33df175bfc5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -441,6 +441,32 @@ pub const fn is_finite(self) -> bool { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(is_subnormal)] + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0_f32; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f32::NAN.is_subnormal()); + /// assert!(!f32::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[unstable(feature = "is_subnormal", issue = "79288")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[inline] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + /// Returns `true` if the number is neither zero, infinite, /// [subnormal], or `NaN`. /// diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 9b1405b479f..b85e8deb6d2 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -440,6 +440,32 @@ pub const fn is_finite(self) -> bool { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(is_subnormal)] + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0_f64; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f64::NAN.is_subnormal()); + /// assert!(!f64::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[unstable(feature = "is_subnormal", issue = "79288")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[inline] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + /// Returns `true` if the number is neither zero, infinite, /// [subnormal], or `NaN`. /// diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 3c2ada57612..a8dea4e9b4e 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -79,7 +79,7 @@ pub trait Index { /// each can be indexed mutably and immutably. /// /// ``` -/// use std::ops::{Index,IndexMut}; +/// use std::ops::{Index, IndexMut}; /// /// #[derive(Debug)] /// enum Side { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 83f22895237..d3af6b9ae6b 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -605,8 +605,9 @@ pub fn reverse(&mut self) { // many bytes away from the end of `self`. // - Any initialized memory is valid `usize`. unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let ptr = self.as_mut_ptr(); + let pa = ptr.add(i); + let pb = ptr.add(ln - i - chunk); let va = ptr::read_unaligned(pa as *mut usize); let vb = ptr::read_unaligned(pb as *mut usize); ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); @@ -635,8 +636,9 @@ pub fn reverse(&mut self) { // always respected, ensuring the `pb` pointer can be used // safely. unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let ptr = self.as_mut_ptr(); + let pa = ptr.add(i); + let pb = ptr.add(ln - i - chunk); let va = ptr::read_unaligned(pa as *mut u32); let vb = ptr::read_unaligned(pb as *mut u32); ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); @@ -654,8 +656,9 @@ pub fn reverse(&mut self) { // aligned, and can be read from and written to. unsafe { // Unsafe swap to avoid the bounds check in safe swap. - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - 1); + let ptr = self.as_mut_ptr(); + let pa = ptr.add(i); + let pb = ptr.add(ln - i - 1); ptr::swap(pa, pb); } i += 1; @@ -1958,10 +1961,10 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)]; /// - /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); - /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); - /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); - /// let r = s.binary_search_by_key(&1, |&(a,b)| b); + /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a, b)| b); /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] @@ -2585,6 +2588,7 @@ pub fn rotate_right(&mut self, k: usize) { /// buf.fill(1); /// assert_eq!(buf, vec![1; 10]); /// ``` + #[doc(alias = "memset")] #[unstable(feature = "slice_fill", issue = "70758")] pub fn fill(&mut self, value: T) where diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 2a54b117ff4..09a9b184e3a 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -893,14 +893,13 @@ pub fn atanh(self) -> f32 { /// # Examples /// /// ``` - /// #![feature(clamp)] /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "clamp", issue = "44095")] + #[stable(feature = "clamp", since = "1.50.0")] #[inline] pub fn clamp(self, min: f32, max: f32) -> f32 { assert!(min <= max); diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 363d1a00476..64bb7cd9fd1 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -895,14 +895,13 @@ pub fn atanh(self) -> f64 { /// # Examples /// /// ``` - /// #![feature(clamp)] /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "clamp", issue = "44095")] + #[stable(feature = "clamp", since = "1.50.0")] #[inline] pub fn clamp(self, min: f64, max: f64) -> f64 { assert!(min <= max); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index db523f05e01..72f19fdce5e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -235,7 +235,6 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(char_internals)] -#![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] @@ -298,7 +297,6 @@ #![feature(raw)] #![feature(raw_ref_macros)] #![feature(ready_macro)] -#![feature(refcell_take)] #![feature(rustc_attrs)] #![feature(rustc_private)] #![feature(shrink_to)] diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index b8377dc1569..b11bd667093 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2332,12 +2332,18 @@ function defocusSearchBar() { var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main"; if (action === "show") { removeClass(relatedDoc, "fns-now-collapsed"); - removeClass(docblock, "hidden-by-usual-hider"); + // Stability information is never hidden. + if (hasClass(docblock, "stability") === false) { + removeClass(docblock, "hidden-by-usual-hider"); + } onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule)); onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule)); } else if (action === "hide") { addClass(relatedDoc, "fns-now-collapsed"); - addClass(docblock, "hidden-by-usual-hider"); + // Stability information should be shown even when detailed info is hidden. + if (hasClass(docblock, "stability") === false) { + addClass(docblock, "hidden-by-usual-hider"); + } onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule)); onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule)); } diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index 2af72f0e987..f698f8835a2 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -5,7 +5,7 @@ // revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph // aux-build:point.rs -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs index 89699bce209..8d98cfac8a4 100644 --- a/src/test/incremental/change_add_field/struct_point.rs +++ b/src/test/incremental/change_add_field/struct_point.rs @@ -5,7 +5,7 @@ // revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 5c024ed91a3..11ba96a8c8d 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -3,7 +3,7 @@ // revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs index c944901e345..a192dff19e9 100644 --- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs @@ -2,7 +2,7 @@ // revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![crate_type = "rlib"] #![feature(rustc_attrs)] diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs index 4a5aac682f5..b0476168555 100644 --- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -2,7 +2,7 @@ // revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![crate_type = "rlib"] #![feature(rustc_attrs)] diff --git a/src/test/incremental/issue-49595/issue-49595.rs b/src/test/incremental/issue-49595/issue-49595.rs index ab4d76eef36..7b1096a64c1 100644 --- a/src/test/incremental/issue-49595/issue-49595.rs +++ b/src/test/incremental/issue-49595/issue-49595.rs @@ -1,6 +1,6 @@ // revisions:cfail1 cfail2 cfail3 // compile-flags: -Z query-dep-graph --test -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![crate_type = "rlib"] diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs index 1208552d256..d42fbf22938 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs @@ -1,14 +1,19 @@ -#![feature(exclusive_range_pattern)] - -use std::usize::MAX; +use std::{isize, usize}; fn main() { - match 0usize { //~ERROR non-exhaustive patterns: `_` not covered - 0..=MAX => {} + match 0usize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `usize` + //~| NOTE `usize` does not have a fixed maximum value + 0..=usize::MAX => {} } - match 0isize { //~ERROR non-exhaustive patterns: `_` not covered - 1..=20 => {} - -5..3 => {} + match 0isize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `isize` + //~| NOTE `isize` does not have a fixed maximum value + isize::MIN..=isize::MAX => {} } } diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index c7a63e5d502..da308c292df 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/feature-gate-precise_pointer_size_matching.rs:6:11 + --> $DIR/feature-gate-precise_pointer_size_matching.rs:4:11 | LL | match 0usize { | ^^^^^^ pattern `_` not covered @@ -10,7 +10,7 @@ LL | match 0usize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11 + --> $DIR/feature-gate-precise_pointer_size_matching.rs:12:11 | LL | match 0isize { | ^^^^^^ pattern `_` not covered diff --git a/src/test/ui/issues/issue-12116.rs b/src/test/ui/issues/issue-12116.rs deleted file mode 100644 index 8b391cd95d7..00000000000 --- a/src/test/ui/issues/issue-12116.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(box_patterns)] -#![feature(box_syntax)] -#![allow(dead_code)] -#![allow(unused_variables)] -#![deny(unreachable_patterns)] - -enum IntList { - Cons(isize, Box), - Nil -} - -fn tail(source_list: &IntList) -> IntList { - match source_list { - &IntList::Cons(val, box ref next_list) => tail(next_list), - &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), -//~^ ERROR unreachable pattern - _ => panic!() - } -} - -fn main() {} diff --git a/src/test/ui/issues/issue-12116.stderr b/src/test/ui/issues/issue-12116.stderr deleted file mode 100644 index 4d162eb77e7..00000000000 --- a/src/test/ui/issues/issue-12116.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unreachable pattern - --> $DIR/issue-12116.rs:15:9 - | -LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-12116.rs:5:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-12369.rs b/src/test/ui/issues/issue-12369.rs deleted file mode 100644 index 0481c1fd9e1..00000000000 --- a/src/test/ui/issues/issue-12369.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![deny(unreachable_patterns)] - -fn main() { - let sl = vec![1,2,3]; - let v: isize = match &*sl { - &[] => 0, - &[a,b,c] => 3, - &[a, ref rest @ ..] => a, - &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern - }; -} diff --git a/src/test/ui/issues/issue-12369.stderr b/src/test/ui/issues/issue-12369.stderr deleted file mode 100644 index aab2be78c9a..00000000000 --- a/src/test/ui/issues/issue-12369.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unreachable pattern - --> $DIR/issue-12369.rs:9:9 - | -LL | &[10,a, ref rest @ ..] => 10 - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-12369.rs:1:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-13727.rs b/src/test/ui/issues/issue-13727.rs deleted file mode 100644 index 7fb565ef3bf..00000000000 --- a/src/test/ui/issues/issue-13727.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![allow(overflowing_literals)] -#![deny(unreachable_patterns)] - -fn test(val: u8) { - match val { - 256 => print!("0b1110\n"), - 512 => print!("0b1111\n"), - //~^ ERROR: unreachable pattern - _ => print!("fail\n"), - } -} - -fn main() { - test(1); -} diff --git a/src/test/ui/issues/issue-13727.stderr b/src/test/ui/issues/issue-13727.stderr deleted file mode 100644 index 07ca56a566f..00000000000 --- a/src/test/ui/issues/issue-13727.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unreachable pattern - --> $DIR/issue-13727.rs:7:5 - | -LL | 512 => print!("0b1111\n"), - | ^^^ - | -note: the lint level is defined here - --> $DIR/issue-13727.rs:2:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-15129.rs b/src/test/ui/issues/issue-15129.rs deleted file mode 100644 index ed134c175ed..00000000000 --- a/src/test/ui/issues/issue-15129.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub enum T { - T1(()), - T2(()) -} - -pub enum V { - V1(isize), - V2(bool) -} - -fn main() { - match (T::T1(()), V::V2(true)) { - //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered - (T::T1(()), V::V1(i)) => (), - (T::T2(()), V::V2(b)) => () - } -} diff --git a/src/test/ui/issues/issue-15129.stderr b/src/test/ui/issues/issue-15129.stderr deleted file mode 100644 index aa4434e72b5..00000000000 --- a/src/test/ui/issues/issue-15129.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered - --> $DIR/issue-15129.rs:12:11 - | -LL | match (T::T1(()), V::V2(true)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(T, V)` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-2111.rs b/src/test/ui/issues/issue-2111.rs deleted file mode 100644 index 7e5835e8697..00000000000 --- a/src/test/ui/issues/issue-2111.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn foo(a: Option, b: Option) { - match (a,b) { - //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered - (Some(a), Some(b)) if a == b => { } - (Some(_), None) | - (None, Some(_)) => { } - } -} - -fn main() { - foo(None, None); -} diff --git a/src/test/ui/issues/issue-2111.stderr b/src/test/ui/issues/issue-2111.stderr deleted file mode 100644 index a39a479e078..00000000000 --- a/src/test/ui/issues/issue-2111.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: `(None, None)` not covered - --> $DIR/issue-2111.rs:2:9 - | -LL | match (a,b) { - | ^^^^^ pattern `(None, None)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(Option, Option)` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-30240-b.rs b/src/test/ui/issues/issue-30240-b.rs deleted file mode 100644 index 01a6e7d8cb9..00000000000 --- a/src/test/ui/issues/issue-30240-b.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![deny(unreachable_patterns)] - -fn main() { - match "world" { - "hello" => {} - _ => {}, - } - - match "world" { - ref _x if false => {} - "hello" => {} - "hello" => {} //~ ERROR unreachable pattern - _ => {}, - } -} diff --git a/src/test/ui/issues/issue-30240-b.stderr b/src/test/ui/issues/issue-30240-b.stderr deleted file mode 100644 index 59d64bc256b..00000000000 --- a/src/test/ui/issues/issue-30240-b.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unreachable pattern - --> $DIR/issue-30240-b.rs:12:9 - | -LL | "hello" => {} - | ^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-30240-b.rs:1:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-30240-rpass.rs b/src/test/ui/issues/issue-30240-rpass.rs deleted file mode 100644 index ab16614fd30..00000000000 --- a/src/test/ui/issues/issue-30240-rpass.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass -fn main() { - let &ref a = &[0i32] as &[_]; - assert_eq!(a, &[0i32] as &[_]); - - let &ref a = "hello"; - assert_eq!(a, "hello"); - - match "foo" { - "fool" => unreachable!(), - "foo" => {}, - ref _x => unreachable!() - } -} diff --git a/src/test/ui/issues/issue-30240.rs b/src/test/ui/issues/issue-30240.rs deleted file mode 100644 index a0c0d1626ec..00000000000 --- a/src/test/ui/issues/issue-30240.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - match "world" { //~ ERROR non-exhaustive patterns: `&_` - "hello" => {} - } - - match "world" { //~ ERROR non-exhaustive patterns: `&_` - ref _x if false => {} - "hello" => {} - } -} diff --git a/src/test/ui/issues/issue-30240.stderr b/src/test/ui/issues/issue-30240.stderr deleted file mode 100644 index a2c58d6e051..00000000000 --- a/src/test/ui/issues/issue-30240.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/issue-30240.rs:2:11 - | -LL | match "world" { - | ^^^^^^^ pattern `&_` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&str` - -error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/issue-30240.rs:6:11 - | -LL | match "world" { - | ^^^^^^^ pattern `&_` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&str` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-3096-1.rs b/src/test/ui/issues/issue-3096-1.rs deleted file mode 100644 index edc3b322305..00000000000 --- a/src/test/ui/issues/issue-3096-1.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - match () { } //~ ERROR non-exhaustive -} diff --git a/src/test/ui/issues/issue-3096-1.stderr b/src/test/ui/issues/issue-3096-1.stderr deleted file mode 100644 index 97c34755189..00000000000 --- a/src/test/ui/issues/issue-3096-1.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: type `()` is non-empty - --> $DIR/issue-3096-1.rs:2:11 - | -LL | match () { } - | ^^ - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `()` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-3096-2.rs b/src/test/ui/issues/issue-3096-2.rs deleted file mode 100644 index a26e425809f..00000000000 --- a/src/test/ui/issues/issue-3096-2.rs +++ /dev/null @@ -1,6 +0,0 @@ -enum Bottom { } - -fn main() { - let x = &() as *const () as *const Bottom; - match x { } //~ ERROR non-exhaustive patterns -} diff --git a/src/test/ui/issues/issue-3096-2.stderr b/src/test/ui/issues/issue-3096-2.stderr deleted file mode 100644 index 472d1a91e6a..00000000000 --- a/src/test/ui/issues/issue-3096-2.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty - --> $DIR/issue-3096-2.rs:5:11 - | -LL | match x { } - | ^ - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `*const Bottom` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 818e004ffc8..d371703e295 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -13,11 +13,13 @@ error[E0599]: no method named `collect` found for struct `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` | - ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL + ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL | LL | pub struct Cloned { | -------------------- doesn't satisfy `_: Iterator` -... + | + ::: $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL + | LL | pub struct TakeWhile { | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | diff --git a/src/test/ui/issues/issue-31221.rs b/src/test/ui/issues/issue-31221.rs deleted file mode 100644 index e03f1ec5bc2..00000000000 --- a/src/test/ui/issues/issue-31221.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(non_snake_case)] -#![deny(unreachable_patterns)] - -#[derive(Clone, Copy)] -enum Enum { - Var1, - Var2, -} - -fn main() { - use Enum::*; - let s = Var1; - match s { - Var1 => (), - Var3 => (), - Var2 => (), - //~^ ERROR unreachable pattern - }; - match &s { - &Var1 => (), - &Var3 => (), - &Var2 => (), - //~^ ERROR unreachable pattern - }; - let t = (Var1, Var1); - match t { - (Var1, b) => (), - (c, d) => (), - anything => () - //~^ ERROR unreachable pattern - }; -} diff --git a/src/test/ui/issues/issue-31221.stderr b/src/test/ui/issues/issue-31221.stderr deleted file mode 100644 index 7d349144456..00000000000 --- a/src/test/ui/issues/issue-31221.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: unreachable pattern - --> $DIR/issue-31221.rs:18:9 - | -LL | Var3 => (), - | ---- matches any value -LL | Var2 => (), - | ^^^^ unreachable pattern - | -note: the lint level is defined here - --> $DIR/issue-31221.rs:4:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/issue-31221.rs:24:9 - | -LL | &Var3 => (), - | ----- matches any value -LL | &Var2 => (), - | ^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/issue-31221.rs:31:9 - | -LL | (c, d) => (), - | ------ matches any value -LL | anything => () - | ^^^^^^^^ unreachable pattern - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/issues/issue-31561.rs b/src/test/ui/issues/issue-31561.rs deleted file mode 100644 index 813b2409cc8..00000000000 --- a/src/test/ui/issues/issue-31561.rs +++ /dev/null @@ -1,10 +0,0 @@ -enum Thing { - Foo(u8), - Bar, - Baz -} - -fn main() { - let Thing::Foo(y) = Thing::Foo(1); - //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered -} diff --git a/src/test/ui/issues/issue-31561.stderr b/src/test/ui/issues/issue-31561.stderr deleted file mode 100644 index 2f562b23692..00000000000 --- a/src/test/ui/issues/issue-31561.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered - --> $DIR/issue-31561.rs:8:9 - | -LL | / enum Thing { -LL | | Foo(u8), -LL | | Bar, - | | --- not covered -LL | | Baz - | | --- not covered -LL | | } - | |_- `Thing` defined here -... -LL | let Thing::Foo(y) = Thing::Foo(1); - | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered - | - = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant - = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `Thing` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ } - | - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/issues/issue-3601.rs b/src/test/ui/issues/issue-3601.rs deleted file mode 100644 index e33359beccd..00000000000 --- a/src/test/ui/issues/issue-3601.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![feature(box_patterns)] -#![feature(box_syntax)] - -struct HTMLImageData { - image: Option -} - -struct ElementData { - kind: Box -} - -enum ElementKind { - HTMLImageElement(HTMLImageData) -} - -enum NodeKind { - Element(ElementData) -} - -struct NodeData { - kind: Box, -} - -fn main() { - let mut id = HTMLImageData { image: None }; - let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) }; - let n = NodeData {kind : box NodeKind::Element(ed)}; - // n.b. span could be better - match n.kind { - box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns - box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true } - }, - }; -} diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr deleted file mode 100644 index c873c20cca8..00000000000 --- a/src/test/ui/issues/issue-3601.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered - --> $DIR/issue-3601.rs:30:44 - | -LL | box NodeKind::Element(ed) => match ed.kind { - | ^^^^^^^ pattern `Box(_, _)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `Box` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-39362.rs b/src/test/ui/issues/issue-39362.rs deleted file mode 100644 index ea3c8f88e0b..00000000000 --- a/src/test/ui/issues/issue-39362.rs +++ /dev/null @@ -1,18 +0,0 @@ -enum Foo { - Bar { bar: Bar, id: usize } -} - -enum Bar { - A, B, C, D, E, F -} - -fn test(f: Foo) { - match f { - //~^ ERROR non-exhaustive patterns - //~| patterns - Foo::Bar { bar: Bar::A, .. } => (), - Foo::Bar { bar: Bar::B, .. } => (), - } -} - -fn main() {} diff --git a/src/test/ui/issues/issue-39362.stderr b/src/test/ui/issues/issue-39362.stderr deleted file mode 100644 index 8c162e55619..00000000000 --- a/src/test/ui/issues/issue-39362.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered - --> $DIR/issue-39362.rs:10:11 - | -LL | / enum Foo { -LL | | Bar { bar: Bar, id: usize } -LL | | } - | |_- `Foo` defined here -... -LL | match f { - | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `Foo` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-4321.rs b/src/test/ui/issues/issue-4321.rs deleted file mode 100644 index 9715f2eba2f..00000000000 --- a/src/test/ui/issues/issue-4321.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let tup = (true, true); - println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered - (false, false) => "foo", - (false, true) => "bar", - (true, true) => "baz" - }); -} diff --git a/src/test/ui/issues/issue-4321.stderr b/src/test/ui/issues/issue-4321.stderr deleted file mode 100644 index 1e8852556b1..00000000000 --- a/src/test/ui/issues/issue-4321.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: `(true, false)` not covered - --> $DIR/issue-4321.rs:3:31 - | -LL | println!("foo {:}", match tup { - | ^^^ pattern `(true, false)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(bool, bool)` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-57472.rs b/src/test/ui/issues/issue-57472.rs deleted file mode 100644 index 1131006374c..00000000000 --- a/src/test/ui/issues/issue-57472.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![crate_type="lib"] -#![deny(unreachable_patterns)] - -mod test_struct { - // Test the exact copy of the minimal example - // posted in the issue. - pub struct Punned { - foo: [u8; 1], - bar: [u8; 1], - } - - pub fn test(punned: Punned) { - match punned { - Punned { foo: [_], .. } => println!("foo"), - Punned { bar: [_], .. } => println!("bar"), - //~^ ERROR unreachable pattern [unreachable_patterns] - } - } -} - -mod test_union { - // Test the same thing using a union. - pub union Punned { - foo: [u8; 1], - bar: [u8; 1], - } - - pub fn test(punned: Punned) { - match punned { - Punned { foo: [_] } => println!("foo"), - Punned { bar: [_] } => println!("bar"), - //~^ ERROR unreachable pattern [unreachable_patterns] - } - } -} diff --git a/src/test/ui/issues/issue-57472.stderr b/src/test/ui/issues/issue-57472.stderr deleted file mode 100644 index 26efdf6dbaf..00000000000 --- a/src/test/ui/issues/issue-57472.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: unreachable pattern - --> $DIR/issue-57472.rs:15:13 - | -LL | Punned { bar: [_], .. } => println!("bar"), - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-57472.rs:2:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/issue-57472.rs:31:13 - | -LL | Punned { bar: [_] } => println!("bar"), - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/issues/issue-73899.rs b/src/test/ui/issues/issue-73899.rs new file mode 100644 index 00000000000..2a3a5ab2a3b --- /dev/null +++ b/src/test/ui/issues/issue-73899.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(const_evaluatable_checked)] +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Foo {} + +impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} + +trait FooImpl {} + +impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {} + +impl FooImpl<{ 0u8 != 0u8 }> for [(); N] {} + +fn foo(_v: T) {} + +fn main() { + foo([]); + foo([()]); +} diff --git a/src/test/ui/match/issue-50900.rs b/src/test/ui/match/issue-50900.rs deleted file mode 100644 index 27135af9575..00000000000 --- a/src/test/ui/match/issue-50900.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[derive(PartialEq, Eq)] -pub struct Tag(pub Context, pub u16); - -#[derive(PartialEq, Eq)] -pub enum Context { - Tiff, - Exif, -} - -impl Tag { - const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665); -} - -fn main() { - match Tag::ExifIFDPointer { - //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered - Tag::ExifIFDPointer => {} - } -} diff --git a/src/test/ui/match/issue-50900.stderr b/src/test/ui/match/issue-50900.stderr deleted file mode 100644 index d378b6e8efe..00000000000 --- a/src/test/ui/match/issue-50900.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered - --> $DIR/issue-50900.rs:15:11 - | -LL | pub struct Tag(pub Context, pub u16); - | ------------------------------------- `Tag` defined here -... -LL | match Tag::ExifIFDPointer { - | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `Tag` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/match/type_polymorphic_byte_str_literals.rs b/src/test/ui/match/type_polymorphic_byte_str_literals.rs deleted file mode 100644 index cb44c1da76b..00000000000 --- a/src/test/ui/match/type_polymorphic_byte_str_literals.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[deny(unreachable_patterns)] - -fn parse_data1(data: &[u8]) -> u32 { - match data { - b"" => 1, - _ => 2, - } -} - -fn parse_data2(data: &[u8]) -> u32 { - match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered - b"" => 1, - } -} - -fn parse_data3(data: &[u8; 0]) -> u8 { - match data { - b"" => 1, - } -} - -fn parse_data4(data: &[u8]) -> u8 { - match data { //~ ERROR non-exhaustive patterns - b"aaa" => 0, - [_, _, _] => 1, - } -} - -fn parse_data5(data: &[u8; 3]) -> u8 { - match data { - b"aaa" => 0, - [_, _, _] => 1, - } -} - -fn main() {} diff --git a/src/test/ui/match/type_polymorphic_byte_str_literals.stderr b/src/test/ui/match/type_polymorphic_byte_str_literals.stderr deleted file mode 100644 index 6ce53a4f21e..00000000000 --- a/src/test/ui/match/type_polymorphic_byte_str_literals.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered - --> $DIR/type_polymorphic_byte_str_literals.rs:11:11 - | -LL | match data { - | ^^^^ pattern `&[_, ..]` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&[u8]` - -error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered - --> $DIR/type_polymorphic_byte_str_literals.rs:23:11 - | -LL | match data { - | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&[u8]` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 0b1fcf58e2e..2efd37b4738 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -15,7 +15,7 @@ LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` | doesn't satisfy `_: FnMut<(&&str,)>` | - ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL + ::: $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL | LL | pub struct Filter { | ----------------------- doesn't satisfy `_: Iterator` diff --git a/src/test/ui/missing/missing-items/issue-40221.rs b/src/test/ui/missing/missing-items/issue-40221.rs deleted file mode 100644 index e1f7e975b80..00000000000 --- a/src/test/ui/missing/missing-items/issue-40221.rs +++ /dev/null @@ -1,16 +0,0 @@ -enum P { - C(PC), -} - -enum PC { - Q, - QA, -} - -fn test(proto: P) { - match proto { //~ ERROR non-exhaustive patterns - P::C(PC::Q) => (), - } -} - -fn main() {} diff --git a/src/test/ui/missing/missing-items/issue-40221.stderr b/src/test/ui/missing/missing-items/issue-40221.stderr deleted file mode 100644 index 98efe805a0b..00000000000 --- a/src/test/ui/missing/missing-items/issue-40221.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0004]: non-exhaustive patterns: `C(QA)` not covered - --> $DIR/issue-40221.rs:11:11 - | -LL | / enum P { -LL | | C(PC), - | | - not covered -LL | | } - | |_- `P` defined here -... -LL | match proto { - | ^^^^^ pattern `C(QA)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `P` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs deleted file mode 100644 index abfacf3936b..00000000000 --- a/src/test/ui/pattern/const-pat-ice.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass - -const FOO: &&&u32 = &&&42; - -fn main() { - match unimplemented!() { - &&&42 => {}, - FOO => {}, - _ => {}, - } -} diff --git a/src/test/ui/pattern/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/deny-irrefutable-let-patterns.rs deleted file mode 100644 index 14040c8ada6..00000000000 --- a/src/test/ui/pattern/deny-irrefutable-let-patterns.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![deny(irrefutable_let_patterns)] - -fn main() { - if let _ = 5 {} //~ ERROR irrefutable if-let pattern - - while let _ = 5 { //~ ERROR irrefutable while-let pattern - break; - } -} diff --git a/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr deleted file mode 100644 index 308a6c7c58e..00000000000 --- a/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: irrefutable if-let pattern - --> $DIR/deny-irrefutable-let-patterns.rs:4:5 - | -LL | if let _ = 5 {} - | ^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/deny-irrefutable-let-patterns.rs:1:9 - | -LL | #![deny(irrefutable_let_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: irrefutable while-let pattern - --> $DIR/deny-irrefutable-let-patterns.rs:6:5 - | -LL | / while let _ = 5 { -LL | | break; -LL | | } - | |_____^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/pattern/integer-range-binding.rs b/src/test/ui/pattern/integer-range-binding.rs new file mode 100644 index 00000000000..ff065882d96 --- /dev/null +++ b/src/test/ui/pattern/integer-range-binding.rs @@ -0,0 +1,8 @@ +// run-pass + +fn main() { + let -2147483648..=2147483647 = 1; + let 0..=255 = 0u8; + let -128..=127 = 0i8; + let '\u{0000}'..='\u{10FFFF}' = 'v'; +} diff --git a/src/test/ui/pattern/irrefutable-let-patterns.rs b/src/test/ui/pattern/irrefutable-let-patterns.rs deleted file mode 100644 index d400ef0bbd6..00000000000 --- a/src/test/ui/pattern/irrefutable-let-patterns.rs +++ /dev/null @@ -1,11 +0,0 @@ -// run-pass - -#![allow(irrefutable_let_patterns)] - -fn main() { - if let _ = 5 {} - - while let _ = 5 { - break; - } -} diff --git a/src/test/ui/pattern/issue-66501.rs b/src/test/ui/pattern/issue-66501.rs deleted file mode 100644 index ffcfd4ad83e..00000000000 --- a/src/test/ui/pattern/issue-66501.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass - -#![allow(unreachable_patterns)] - -fn main() { - const CONST: &[Option<()>; 1] = &[Some(())]; - match &[Some(())] { - &[None] => {} - CONST => {} - &[Some(())] => {} - } -} diff --git a/src/test/ui/pattern/usefulness/const-pat-ice.rs b/src/test/ui/pattern/usefulness/const-pat-ice.rs new file mode 100644 index 00000000000..abfacf3936b --- /dev/null +++ b/src/test/ui/pattern/usefulness/const-pat-ice.rs @@ -0,0 +1,11 @@ +// check-pass + +const FOO: &&&u32 = &&&42; + +fn main() { + match unimplemented!() { + &&&42 => {}, + FOO => {}, + _ => {}, + } +} diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs new file mode 100644 index 00000000000..14040c8ada6 --- /dev/null +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs @@ -0,0 +1,9 @@ +#![deny(irrefutable_let_patterns)] + +fn main() { + if let _ = 5 {} //~ ERROR irrefutable if-let pattern + + while let _ = 5 { //~ ERROR irrefutable while-let pattern + break; + } +} diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr new file mode 100644 index 00000000000..308a6c7c58e --- /dev/null +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr @@ -0,0 +1,22 @@ +error: irrefutable if-let pattern + --> $DIR/deny-irrefutable-let-patterns.rs:4:5 + | +LL | if let _ = 5 {} + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/deny-irrefutable-let-patterns.rs:1:9 + | +LL | #![deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: irrefutable while-let pattern + --> $DIR/deny-irrefutable-let-patterns.rs:6:5 + | +LL | / while let _ = 5 { +LL | | break; +LL | | } + | |_____^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs deleted file mode 100644 index 78cc0d28fb0..00000000000 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs +++ /dev/null @@ -1,172 +0,0 @@ -#![feature(precise_pointer_size_matching)] -#![feature(exclusive_range_pattern)] -#![deny(unreachable_patterns)] -#![deny(overlapping_patterns)] - -use std::{char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128}; - -fn main() { - let x: u8 = 0; - - // A single range covering the entire domain. - match x { - 0 ..= 255 => {} // ok - } - - // A combination of ranges and values. - // These are currently allowed to be overlapping. - match x { - 0 ..= 32 => {} - 33 => {} - 34 .. 128 => {} - 100 ..= 200 => {} - 200 => {} //~ ERROR unreachable pattern - 201 ..= 255 => {} - } - - // An incomplete set of values. - match x { //~ ERROR non-exhaustive patterns - 0 .. 128 => {} - } - - // A more incomplete set of values. - match x { //~ ERROR non-exhaustive patterns - 0 ..= 10 => {} - 20 ..= 30 => {} - 35 => {} - 70 .. 255 => {} - } - - let x: i8 = 0; - match x { //~ ERROR non-exhaustive patterns - -7 => {} - -5..=120 => {} - -2..=20 => {} - //~^ ERROR unreachable pattern - 125 => {} - } - - // Let's test other types too! - let c: char = '\u{0}'; - match c { - '\u{0}' ..= char::MAX => {} // ok - } - - // We can actually get away with just covering the - // following two ranges, which correspond to all - // valid Unicode Scalar Values. - match c { - '\u{0000}' ..= '\u{D7FF}' => {} - '\u{E000}' ..= '\u{10_FFFF}' => {} - } - - match 0u16 { - 0 ..= u16::MAX => {} // ok - } - - match 0u32 { - 0 ..= u32::MAX => {} // ok - } - - match 0u64 { - 0 ..= u64::MAX => {} // ok - } - - match 0u128 { - 0 ..= u128::MAX => {} // ok - } - - match 0i8 { - -128 ..= 127 => {} // ok - } - - match 0i8 { //~ ERROR non-exhaustive patterns - -127 ..= 127 => {} - } - - match 0i16 { - i16::MIN ..= i16::MAX => {} // ok - } - - match 0i16 { //~ ERROR non-exhaustive patterns - i16::MIN ..= -1 => {} - 1 ..= i16::MAX => {} - } - - match 0i32 { - i32::MIN ..= i32::MAX => {} // ok - } - - match 0i64 { - i64::MIN ..= i64::MAX => {} // ok - } - - match 0i128 { - i128::MIN ..= i128::MAX => {} // ok - } - - // Make sure that guards don't factor into the exhaustiveness checks. - match 0u8 { //~ ERROR non-exhaustive patterns - 0 .. 128 => {} - 128 ..= 255 if true => {} - } - - match 0u8 { - 0 .. 128 => {} - 128 ..= 255 if false => {} - 128 ..= 255 => {} // ok, because previous arm was guarded - } - - // Now things start getting a bit more interesting. Testing products! - match (0u8, Some(())) { //~ ERROR non-exhaustive patterns - (1, _) => {} - (_, None) => {} - } - - match (0u8, true) { //~ ERROR non-exhaustive patterns - (0 ..= 125, false) => {} - (128 ..= 255, false) => {} - (0 ..= 255, true) => {} - } - - match (0u8, true) { // ok - (0 ..= 125, false) => {} - (128 ..= 255, false) => {} - (0 ..= 255, true) => {} - (125 .. 128, false) => {} - } - - match 0u8 { - 0 .. 2 => {} - 1 ..= 2 => {} //~ ERROR multiple patterns covering the same range - _ => {} - } - - const LIM: u128 = u128::MAX - 1; - match 0u128 { //~ ERROR non-exhaustive patterns - 0 ..= LIM => {} - } - - match 0u128 { //~ ERROR non-exhaustive patterns - 0 ..= 4 => {} - } - - match 0u128 { //~ ERROR non-exhaustive patterns - 4 ..= u128::MAX => {} - } - - const FOO: i32 = 42; - const BAR: &i32 = &42; - match &0 { - &42 => {} - &FOO => {} //~ ERROR unreachable pattern - BAR => {} //~ ERROR unreachable pattern - _ => {} - } - - // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933 - match &0 { - BAR => {} // ok - _ => {} - } -} diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr deleted file mode 100644 index 9f076c50a8f..00000000000 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ /dev/null @@ -1,146 +0,0 @@ -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:23:9 - | -LL | 200 => {} - | ^^^ - | -note: the lint level is defined here - --> $DIR/exhaustive_integer_patterns.rs:3:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:28:11 - | -LL | match x { - | ^ pattern `128_u8..=u8::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u8` - -error[E0004]: non-exhaustive patterns: `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered - --> $DIR/exhaustive_integer_patterns.rs:33:11 - | -LL | match x { - | ^ patterns `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u8` - -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:44:9 - | -LL | -2..=20 => {} - | ^^^^^^^ - -error[E0004]: non-exhaustive patterns: `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered - --> $DIR/exhaustive_integer_patterns.rs:41:11 - | -LL | match x { - | ^ patterns `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `i8` - -error[E0004]: non-exhaustive patterns: `i8::MIN` not covered - --> $DIR/exhaustive_integer_patterns.rs:83:11 - | -LL | match 0i8 { - | ^^^ pattern `i8::MIN` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `i8` - -error[E0004]: non-exhaustive patterns: `0_i16` not covered - --> $DIR/exhaustive_integer_patterns.rs:91:11 - | -LL | match 0i16 { - | ^^^^ pattern `0_i16` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `i16` - -error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:109:11 - | -LL | match 0u8 { - | ^^^ pattern `128_u8..=u8::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u8` - -error[E0004]: non-exhaustive patterns: `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered - --> $DIR/exhaustive_integer_patterns.rs:121:11 - | -LL | match (0u8, Some(())) { - | ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(u8, Option<()>)` - -error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered - --> $DIR/exhaustive_integer_patterns.rs:126:11 - | -LL | match (0u8, true) { - | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(u8, bool)` - -error: multiple patterns covering the same range - --> $DIR/exhaustive_integer_patterns.rs:141:9 - | -LL | 0 .. 2 => {} - | ------ this range overlaps on `1_u8` -LL | 1 ..= 2 => {} - | ^^^^^^^ overlapping patterns - | -note: the lint level is defined here - --> $DIR/exhaustive_integer_patterns.rs:4:9 - | -LL | #![deny(overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:146:11 - | -LL | match 0u128 { - | ^^^^^ pattern `u128::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u128` - -error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:150:11 - | -LL | match 0u128 { - | ^^^^^ pattern `5_u128..=u128::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u128` - -error[E0004]: non-exhaustive patterns: `0_u128..=3_u128` not covered - --> $DIR/exhaustive_integer_patterns.rs:154:11 - | -LL | match 0u128 { - | ^^^^^ pattern `0_u128..=3_u128` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u128` - -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:162:9 - | -LL | &FOO => {} - | ^^^^ - -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:163:9 - | -LL | BAR => {} - | ^^^ - -error: aborting due to 16 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/floats.rs b/src/test/ui/pattern/usefulness/floats.rs new file mode 100644 index 00000000000..095f5ac9a89 --- /dev/null +++ b/src/test/ui/pattern/usefulness/floats.rs @@ -0,0 +1,19 @@ +#![allow(illegal_floating_point_literal_pattern)] +#![deny(unreachable_patterns)] + +fn main() { + match 0.0 { + 0.0..=1.0 => {} + _ => {} // ok + } + + match 0.0 { //~ ERROR non-exhaustive patterns + 0.0..=1.0 => {} + } + + match 1.0f64 { + 0.01f64 ..= 6.5f64 => {} + 0.02f64 => {} //~ ERROR unreachable pattern + _ => {} + }; +} diff --git a/src/test/ui/pattern/usefulness/floats.stderr b/src/test/ui/pattern/usefulness/floats.stderr new file mode 100644 index 00000000000..464bfbdb2c3 --- /dev/null +++ b/src/test/ui/pattern/usefulness/floats.stderr @@ -0,0 +1,24 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/floats.rs:10:11 + | +LL | match 0.0 { + | ^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `f64` + +error: unreachable pattern + --> $DIR/floats.rs:16:7 + | +LL | 0.02f64 => {} + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/floats.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/guards-not-exhaustive.rs b/src/test/ui/pattern/usefulness/guards-not-exhaustive.rs deleted file mode 100644 index b74f162c0c6..00000000000 --- a/src/test/ui/pattern/usefulness/guards-not-exhaustive.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-pass - -#![allow(non_snake_case)] - -#[derive(Copy, Clone)] -enum Q { R(Option) } - -fn xyzzy(q: Q) -> usize { - match q { - Q::R(S) if S.is_some() => { 0 } - _ => 1 - } -} - - -pub fn main() { - assert_eq!(xyzzy(Q::R(Some(5))), 0); -} diff --git a/src/test/ui/pattern/usefulness/guards.rs b/src/test/ui/pattern/usefulness/guards.rs new file mode 100644 index 00000000000..b15440cf608 --- /dev/null +++ b/src/test/ui/pattern/usefulness/guards.rs @@ -0,0 +1,22 @@ +#![feature(exclusive_range_pattern)] +#![deny(unreachable_patterns)] + +enum Q { R(Option) } + +pub fn main() { + match Q::R(None) { + Q::R(S) if S.is_some() => {} + _ => {} + } + + match 0u8 { //~ ERROR non-exhaustive patterns + 0 .. 128 => {} + 128 ..= 255 if true => {} + } + + match 0u8 { + 0 .. 128 => {} + 128 ..= 255 if false => {} + 128 ..= 255 => {} // ok, because previous arm was guarded + } +} diff --git a/src/test/ui/pattern/usefulness/guards.stderr b/src/test/ui/pattern/usefulness/guards.stderr new file mode 100644 index 00000000000..61f7facb330 --- /dev/null +++ b/src/test/ui/pattern/usefulness/guards.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered + --> $DIR/guards.rs:12:11 + | +LL | match 0u8 { + | ^^^ pattern `128_u8..=u8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs new file mode 100644 index 00000000000..5a44dfc28bb --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs @@ -0,0 +1,101 @@ +#![feature(exclusive_range_pattern)] +#![feature(assoc_char_consts)] +#![deny(unreachable_patterns)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +macro_rules! test_int { + ($s:expr, $min:path, $max:path) => { + m!($s, $min..=$max); + m!($s, $min..5 | 5..=$max); + m!($s, $min..=4 | 5..=$max); + m!($s, $min..$max | $max); + m!(($s, true), ($min..5, true) | (5..=$max, true) | ($min..=$max, false)); + } +} + +fn main() { + test_int!(0u8, u8::MIN, u8::MAX); + test_int!(0u16, u16::MIN, u16::MAX); + test_int!(0u32, u32::MIN, u32::MAX); + test_int!(0u64, u64::MIN, u64::MAX); + test_int!(0u128, u128::MIN, u128::MAX); + + test_int!(0i8, i8::MIN, i8::MAX); + test_int!(0i16, i16::MIN, i16::MAX); + test_int!(0i32, i32::MIN, i32::MAX); + test_int!(0i64, i64::MIN, i64::MAX); + test_int!(0i128, i128::MIN, i128::MAX); + + m!('a', '\u{0}'..=char::MAX); + m!('a', '\u{0}'..='\u{10_FFFF}'); + // We can get away with just covering the following two ranges, which correspond to all valid + // Unicode Scalar Values. + m!('a', '\u{0}'..='\u{D7FF}' | '\u{E000}'..=char::MAX); + m!('a', '\u{0}'..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..=char::MAX); + + let 0..=255 = 0u8; + let -128..=127 = 0i8; + let -2147483648..=2147483647 = 0i32; + let '\u{0000}'..='\u{10FFFF}' = 'v'; + + // Almost exhaustive + m!(0u8, 0..255); //~ ERROR non-exhaustive patterns + m!(0u8, 0..=254); //~ ERROR non-exhaustive patterns + m!(0u8, 1..=255); //~ ERROR non-exhaustive patterns + m!(0u8, 0..42 | 43..=255); //~ ERROR non-exhaustive patterns + m!(0i8, -128..127); //~ ERROR non-exhaustive patterns + m!(0i8, -128..=126); //~ ERROR non-exhaustive patterns + m!(0i8, -127..=127); //~ ERROR non-exhaustive patterns + match 0i8 { //~ ERROR non-exhaustive patterns + i8::MIN ..= -1 => {} + 1 ..= i8::MAX => {} + } + const ALMOST_MAX: u128 = u128::MAX - 1; + m!(0u128, 0..=ALMOST_MAX); //~ ERROR non-exhaustive patterns + m!(0u128, 0..=4); //~ ERROR non-exhaustive patterns + m!(0u128, 1..=u128::MAX); //~ ERROR non-exhaustive patterns + + // More complicatedly (non-)exhaustive + match 0u8 { + 0 ..= 30 => {} + 20 ..= 70 => {} + 50 ..= 255 => {} + } + match (0u8, true) { //~ ERROR non-exhaustive patterns + (0 ..= 125, false) => {} + (128 ..= 255, false) => {} + (0 ..= 255, true) => {} + } + match (0u8, true) { // ok + (0 ..= 125, false) => {} + (128 ..= 255, false) => {} + (0 ..= 255, true) => {} + (125 .. 128, false) => {} + } + match (true, 0u8) { + (true, 0 ..= 255) => {} + (false, 0 ..= 125) => {} + (false, 128 ..= 255) => {} + (false, 125 .. 128) => {} + } + match Some(0u8) { + None => {} + Some(0 ..= 125) => {} + Some(128 ..= 255) => {} + Some(125 .. 128) => {} + } + const FOO: u8 = 41; + const BAR: &u8 = &42; + match &0u8 { + 0..41 => {} + &FOO => {} + BAR => {} + 43..=255 => {} + } + +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr new file mode 100644 index 00000000000..2e0023348e4 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -0,0 +1,111 @@ +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered + --> $DIR/exhaustiveness.rs:47:8 + | +LL | m!(0u8, 0..255); + | ^^^ pattern `u8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered + --> $DIR/exhaustiveness.rs:48:8 + | +LL | m!(0u8, 0..=254); + | ^^^ pattern `u8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `0_u8` not covered + --> $DIR/exhaustiveness.rs:49:8 + | +LL | m!(0u8, 1..=255); + | ^^^ pattern `0_u8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `42_u8` not covered + --> $DIR/exhaustiveness.rs:50:8 + | +LL | m!(0u8, 0..42 | 43..=255); + | ^^^ pattern `42_u8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered + --> $DIR/exhaustiveness.rs:51:8 + | +LL | m!(0i8, -128..127); + | ^^^ pattern `i8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered + --> $DIR/exhaustiveness.rs:52:8 + | +LL | m!(0i8, -128..=126); + | ^^^ pattern `i8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `i8::MIN` not covered + --> $DIR/exhaustiveness.rs:53:8 + | +LL | m!(0i8, -127..=127); + | ^^^ pattern `i8::MIN` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `0_i8` not covered + --> $DIR/exhaustiveness.rs:54:11 + | +LL | match 0i8 { + | ^^^ pattern `0_i8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `u128::MAX` not covered + --> $DIR/exhaustiveness.rs:59:8 + | +LL | m!(0u128, 0..=ALMOST_MAX); + | ^^^^^ pattern `u128::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u128` + +error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered + --> $DIR/exhaustiveness.rs:60:8 + | +LL | m!(0u128, 0..=4); + | ^^^^^ pattern `5_u128..=u128::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u128` + +error[E0004]: non-exhaustive patterns: `0_u128` not covered + --> $DIR/exhaustiveness.rs:61:8 + | +LL | m!(0u128, 1..=u128::MAX); + | ^^^^^ pattern `0_u128` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u128` + +error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered + --> $DIR/exhaustiveness.rs:69:11 + | +LL | match (0u8, true) { + | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(u8, bool)` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs new file mode 100644 index 00000000000..af720a05693 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -0,0 +1,53 @@ +#![feature(exclusive_range_pattern)] +#![deny(overlapping_patterns)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + } +} + +fn main() { + m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns covering the same range + m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns covering the same range + m!(0u8, 20..=30, 31..=40); + m!(0u8, 20..=30, 29..=40); + m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns covering the same range + m!(0u8, 20.. 30, 28..=40); + m!(0u8, 20.. 30, 30..=40); + m!(0u8, 20..=30, 30..=30); + m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns covering the same range + m!(0u8, 20..=30, 29..=30); + m!(0u8, 20..=30, 20..=20); + m!(0u8, 20..=30, 20..=21); + m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns covering the same range + m!(0u8, 20..=30, 20); + m!(0u8, 20..=30, 25); + m!(0u8, 20..=30, 30); + m!(0u8, 20.. 30, 29); + m!(0u8, 20, 20..=30); //~ ERROR multiple patterns covering the same range + m!(0u8, 25, 20..=30); + m!(0u8, 30, 20..=30); //~ ERROR multiple patterns covering the same range + + match (0u8, true) { + (0..=10, true) => {} + (10..20, true) => {} // not detected + (10..20, false) => {} + _ => {} + } + match (true, 0u8) { + (true, 0..=10) => {} + (true, 10..20) => {} //~ ERROR multiple patterns covering the same range + (false, 10..20) => {} + _ => {} + } + match Some(0u8) { + Some(0..=10) => {} + Some(10..20) => {} //~ ERROR multiple patterns covering the same range + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr new file mode 100644 index 00000000000..7bb747cdf6f --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -0,0 +1,80 @@ +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:15:22 + | +LL | m!(0u8, 20..=30, 30..=40); + | ------- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `30_u8` + | +note: the lint level is defined here + --> $DIR/overlapping_range_endpoints.rs:2:9 + | +LL | #![deny(overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:16:22 + | +LL | m!(0u8, 30..=40, 20..=30); + | ------- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `30_u8` + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:19:22 + | +LL | m!(0u8, 20.. 30, 29..=40); + | ------- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `29_u8` + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:23:22 + | +LL | m!(0u8, 20..=30, 30..=31); + | ------- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `30_u8` + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:27:22 + | +LL | m!(0u8, 20..=30, 19..=20); + | ------- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `20_u8` + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:32:17 + | +LL | m!(0u8, 20, 20..=30); + | -- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `20_u8` + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:34:17 + | +LL | m!(0u8, 30, 20..=30); + | -- ^^^^^^^ overlapping patterns + | | + | this range overlaps on `30_u8` + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:44:16 + | +LL | (true, 0..=10) => {} + | ------ this range overlaps on `10_u8` +LL | (true, 10..20) => {} + | ^^^^^^ overlapping patterns + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:50:14 + | +LL | Some(0..=10) => {} + | ------ this range overlaps on `10_u8` +LL | Some(10..20) => {} + | ^^^^^^ overlapping patterns + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs new file mode 100644 index 00000000000..6173053cc4f --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs @@ -0,0 +1,38 @@ +#![feature(precise_pointer_size_matching)] +#![feature(exclusive_range_pattern)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +fn main() { + match 0usize { + 0 ..= usize::MAX => {} + } + + match 0isize { + isize::MIN ..= isize::MAX => {} + } + + m!(0usize, 0..=usize::MAX); + m!(0usize, 0..5 | 5..=usize::MAX); + m!(0usize, 0..usize::MAX | usize::MAX); + m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + + m!(0isize, isize::MIN..=isize::MAX); + m!(0isize, isize::MIN..5 | 5..=isize::MAX); + m!(0isize, isize::MIN..isize::MAX | isize::MAX); + m!((0isize, true), (isize::MIN..5, true) + | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)); + + match 0isize { + isize::MIN ..= -1 => {} + 0 => {} + 1 ..= isize::MAX => {} + } + + match 7usize {} + //~^ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr new file mode 100644 index 00000000000..0b3c65166ee --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/pointer-sized-int-allow.rs:36:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs new file mode 100644 index 00000000000..9292f22e09e --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs @@ -0,0 +1,48 @@ +#![feature(exclusive_range_pattern)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +fn main() { + match 0usize { + //~^ ERROR non-exhaustive patterns + 0 ..= usize::MAX => {} + } + + match 0isize { + //~^ ERROR non-exhaustive patterns + isize::MIN ..= isize::MAX => {} + } + + m!(0usize, 0..=usize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0usize, 0..5 | 5..=usize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0usize, 0..usize::MAX | usize::MAX); + //~^ ERROR non-exhaustive patterns + m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + //~^ ERROR non-exhaustive patterns + + m!(0isize, isize::MIN..=isize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..5 | 5..=isize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..isize::MAX | isize::MAX); + //~^ ERROR non-exhaustive patterns + m!((0isize, true), (isize::MIN..5, true) + | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)); + //~^^ ERROR non-exhaustive patterns + + match 0isize { + //~^ ERROR non-exhaustive patterns + isize::MIN ..= -1 => {} + 0 => {} + 1 ..= isize::MAX => {} + } + + match 7usize {} + //~^ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr new file mode 100644 index 00000000000..9d566b0e775 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr @@ -0,0 +1,129 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:10:11 + | +LL | match 0usize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:15:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:20:8 + | +LL | m!(0usize, 0..=usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:22:8 + | +LL | m!(0usize, 0..5 | 5..=usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:24:8 + | +LL | m!(0usize, 0..usize::MAX | usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `(_, _)` not covered + --> $DIR/pointer-sized-int-deny.rs:26:8 + | +LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(usize, bool)` + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:29:8 + | +LL | m!(0isize, isize::MIN..=isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:31:8 + | +LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:33:8 + | +LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `(_, _)` not covered + --> $DIR/pointer-sized-int-deny.rs:35:8 + | +LL | m!((0isize, true), (isize::MIN..5, true) + | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(isize, bool)` + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:39:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/pointer-sized-int-deny.rs:46:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs new file mode 100644 index 00000000000..a2aa655ca54 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs @@ -0,0 +1,18 @@ +// This tests that the lint message explains the reason for the error. +fn main() { + match 0usize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `usize` + //~| NOTE `usize` does not have a fixed maximum value + 0..=usize::MAX => {} + } + + match 0isize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `isize` + //~| NOTE `isize` does not have a fixed maximum value + isize::MIN..=isize::MAX => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr new file mode 100644 index 00000000000..37e73a68f22 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr @@ -0,0 +1,25 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/precise_pointer_matching-message.rs:3:11 + | +LL | match 0usize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/precise_pointer_matching-message.rs:11:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs new file mode 100644 index 00000000000..9078e65f667 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs @@ -0,0 +1,112 @@ +#![feature(exclusive_range_pattern)] +#![deny(unreachable_patterns)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + } +} + +fn main() { + m!(0u8, 42, 41); + m!(0u8, 42, 42); //~ ERROR unreachable pattern + m!(0u8, 42, 43); + + m!(0u8, 20..=30, 19); + m!(0u8, 20..=30, 20); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 21); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 25); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 29); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 31); + m!(0u8, 20..30, 19); + m!(0u8, 20..30, 20); //~ ERROR unreachable pattern + m!(0u8, 20..30, 21); //~ ERROR unreachable pattern + m!(0u8, 20..30, 25); //~ ERROR unreachable pattern + m!(0u8, 20..30, 29); //~ ERROR unreachable pattern + m!(0u8, 20..30, 30); + m!(0u8, 20..30, 31); + + m!(0u8, 20..=30, 20..=30); //~ ERROR unreachable pattern + m!(0u8, 20.. 30, 20.. 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20.. 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 19..=30); + m!(0u8, 20..=30, 21..=30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20..=29); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20..=31); + m!('a', 'A'..='z', 'a'..='z'); //~ ERROR unreachable pattern + + match 0u8 { + 5 => {}, + 6 => {}, + 7 => {}, + 8 => {}, + 5..=8 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10..20 => {}, + 5..15 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10..20 => {}, + 20..30 => {}, + 5..25 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10 => {}, + 11..=23 => {}, + 19..30 => {}, + 5..25 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0usize { + 0..10 => {}, + 10..20 => {}, + 5..15 => {}, // FIXME: should be unreachable + _ => {}, + } + // Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are + // allowed. + match 'a' { + _ => {}, + '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern + } + match 'a' { + '\u{0}'..='\u{D7FF}' => {}, + '\u{E000}'..='\u{10_FFFF}' => {}, + '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable + } + + match (0u8, true) { + (0..=255, false) => {} + (0..=255, true) => {} // ok + } + match (true, 0u8) { + (false, 0..=255) => {} + (true, 0..=255) => {} // ok + } + + const FOO: i32 = 42; + const BAR: &i32 = &42; + match &0 { + &42 => {} + &FOO => {} //~ ERROR unreachable pattern + BAR => {} //~ ERROR unreachable pattern + _ => {} + } + // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933 + match &0 { + BAR => {} // ok + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr new file mode 100644 index 00000000000..8baf0d50c88 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -0,0 +1,146 @@ +error: unreachable pattern + --> $DIR/reachability.rs:16:17 + | +LL | m!(0u8, 42, 42); + | ^^ + | +note: the lint level is defined here + --> $DIR/reachability.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:20:22 + | +LL | m!(0u8, 20..=30, 20); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:21:22 + | +LL | m!(0u8, 20..=30, 21); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:22:22 + | +LL | m!(0u8, 20..=30, 25); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:23:22 + | +LL | m!(0u8, 20..=30, 29); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:24:22 + | +LL | m!(0u8, 20..=30, 30); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:27:21 + | +LL | m!(0u8, 20..30, 20); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:28:21 + | +LL | m!(0u8, 20..30, 21); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:29:21 + | +LL | m!(0u8, 20..30, 25); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:30:21 + | +LL | m!(0u8, 20..30, 29); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:34:22 + | +LL | m!(0u8, 20..=30, 20..=30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:35:22 + | +LL | m!(0u8, 20.. 30, 20.. 30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:36:22 + | +LL | m!(0u8, 20..=30, 20.. 30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:38:22 + | +LL | m!(0u8, 20..=30, 21..=30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:39:22 + | +LL | m!(0u8, 20..=30, 20..=29); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:41:24 + | +LL | m!('a', 'A'..='z', 'a'..='z'); + | ^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:48:9 + | +LL | 5..=8 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:54:9 + | +LL | 5..15 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:61:9 + | +LL | 5..25 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:69:9 + | +LL | 5..25 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:82:9 + | +LL | '\u{D7FF}'..='\u{E000}' => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:103:9 + | +LL | &FOO => {} + | ^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:104:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 23 previous errors + diff --git a/src/test/ui/pattern/usefulness/irrefutable-exhaustive-integer-binding.rs b/src/test/ui/pattern/usefulness/irrefutable-exhaustive-integer-binding.rs deleted file mode 100644 index ff065882d96..00000000000 --- a/src/test/ui/pattern/usefulness/irrefutable-exhaustive-integer-binding.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - -fn main() { - let -2147483648..=2147483647 = 1; - let 0..=255 = 0u8; - let -128..=127 = 0i8; - let '\u{0000}'..='\u{10FFFF}' = 'v'; -} diff --git a/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs new file mode 100644 index 00000000000..d400ef0bbd6 --- /dev/null +++ b/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs @@ -0,0 +1,11 @@ +// run-pass + +#![allow(irrefutable_let_patterns)] + +fn main() { + if let _ = 5 {} + + while let _ = 5 { + break; + } +} diff --git a/src/test/ui/pattern/usefulness/issue-12116.rs b/src/test/ui/pattern/usefulness/issue-12116.rs new file mode 100644 index 00000000000..8b391cd95d7 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12116.rs @@ -0,0 +1,21 @@ +#![feature(box_patterns)] +#![feature(box_syntax)] +#![allow(dead_code)] +#![allow(unused_variables)] +#![deny(unreachable_patterns)] + +enum IntList { + Cons(isize, Box), + Nil +} + +fn tail(source_list: &IntList) -> IntList { + match source_list { + &IntList::Cons(val, box ref next_list) => tail(next_list), + &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), +//~^ ERROR unreachable pattern + _ => panic!() + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-12116.stderr b/src/test/ui/pattern/usefulness/issue-12116.stderr new file mode 100644 index 00000000000..4d162eb77e7 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12116.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-12116.rs:15:9 + | +LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-12116.rs:5:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-12369.rs b/src/test/ui/pattern/usefulness/issue-12369.rs new file mode 100644 index 00000000000..0481c1fd9e1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12369.rs @@ -0,0 +1,11 @@ +#![deny(unreachable_patterns)] + +fn main() { + let sl = vec![1,2,3]; + let v: isize = match &*sl { + &[] => 0, + &[a,b,c] => 3, + &[a, ref rest @ ..] => a, + &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-12369.stderr b/src/test/ui/pattern/usefulness/issue-12369.stderr new file mode 100644 index 00000000000..aab2be78c9a --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12369.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-12369.rs:9:9 + | +LL | &[10,a, ref rest @ ..] => 10 + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-12369.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-13727.rs b/src/test/ui/pattern/usefulness/issue-13727.rs new file mode 100644 index 00000000000..7fb565ef3bf --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-13727.rs @@ -0,0 +1,15 @@ +#![allow(overflowing_literals)] +#![deny(unreachable_patterns)] + +fn test(val: u8) { + match val { + 256 => print!("0b1110\n"), + 512 => print!("0b1111\n"), + //~^ ERROR: unreachable pattern + _ => print!("fail\n"), + } +} + +fn main() { + test(1); +} diff --git a/src/test/ui/pattern/usefulness/issue-13727.stderr b/src/test/ui/pattern/usefulness/issue-13727.stderr new file mode 100644 index 00000000000..07ca56a566f --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-13727.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-13727.rs:7:5 + | +LL | 512 => print!("0b1111\n"), + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-13727.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs new file mode 100644 index 00000000000..ed134c175ed --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -0,0 +1,17 @@ +pub enum T { + T1(()), + T2(()) +} + +pub enum V { + V1(isize), + V2(bool) +} + +fn main() { + match (T::T1(()), V::V2(true)) { + //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered + (T::T1(()), V::V1(i)) => (), + (T::T2(()), V::V2(b)) => () + } +} diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr new file mode 100644 index 00000000000..aa4434e72b5 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-15129.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered + --> $DIR/issue-15129.rs:12:11 + | +LL | match (T::T1(()), V::V2(true)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(T, V)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-2111.rs b/src/test/ui/pattern/usefulness/issue-2111.rs new file mode 100644 index 00000000000..7e5835e8697 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-2111.rs @@ -0,0 +1,12 @@ +fn foo(a: Option, b: Option) { + match (a,b) { + //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered + (Some(a), Some(b)) if a == b => { } + (Some(_), None) | + (None, Some(_)) => { } + } +} + +fn main() { + foo(None, None); +} diff --git a/src/test/ui/pattern/usefulness/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr new file mode 100644 index 00000000000..a39a479e078 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-2111.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: `(None, None)` not covered + --> $DIR/issue-2111.rs:2:9 + | +LL | match (a,b) { + | ^^^^^ pattern `(None, None)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(Option, Option)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-30240-b.rs b/src/test/ui/pattern/usefulness/issue-30240-b.rs new file mode 100644 index 00000000000..01a6e7d8cb9 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240-b.rs @@ -0,0 +1,15 @@ +#![deny(unreachable_patterns)] + +fn main() { + match "world" { + "hello" => {} + _ => {}, + } + + match "world" { + ref _x if false => {} + "hello" => {} + "hello" => {} //~ ERROR unreachable pattern + _ => {}, + } +} diff --git a/src/test/ui/pattern/usefulness/issue-30240-b.stderr b/src/test/ui/pattern/usefulness/issue-30240-b.stderr new file mode 100644 index 00000000000..59d64bc256b --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240-b.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-30240-b.rs:12:9 + | +LL | "hello" => {} + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-30240-b.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-30240-rpass.rs b/src/test/ui/pattern/usefulness/issue-30240-rpass.rs new file mode 100644 index 00000000000..ab16614fd30 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240-rpass.rs @@ -0,0 +1,14 @@ +// run-pass +fn main() { + let &ref a = &[0i32] as &[_]; + assert_eq!(a, &[0i32] as &[_]); + + let &ref a = "hello"; + assert_eq!(a, "hello"); + + match "foo" { + "fool" => unreachable!(), + "foo" => {}, + ref _x => unreachable!() + } +} diff --git a/src/test/ui/pattern/usefulness/issue-30240.rs b/src/test/ui/pattern/usefulness/issue-30240.rs new file mode 100644 index 00000000000..a0c0d1626ec --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240.rs @@ -0,0 +1,10 @@ +fn main() { + match "world" { //~ ERROR non-exhaustive patterns: `&_` + "hello" => {} + } + + match "world" { //~ ERROR non-exhaustive patterns: `&_` + ref _x if false => {} + "hello" => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-30240.stderr b/src/test/ui/pattern/usefulness/issue-30240.stderr new file mode 100644 index 00000000000..a2c58d6e051 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/issue-30240.rs:2:11 + | +LL | match "world" { + | ^^^^^^^ pattern `&_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&str` + +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/issue-30240.rs:6:11 + | +LL | match "world" { + | ^^^^^^^ pattern `&_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-3096-1.rs b/src/test/ui/pattern/usefulness/issue-3096-1.rs new file mode 100644 index 00000000000..edc3b322305 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-1.rs @@ -0,0 +1,3 @@ +fn main() { + match () { } //~ ERROR non-exhaustive +} diff --git a/src/test/ui/pattern/usefulness/issue-3096-1.stderr b/src/test/ui/pattern/usefulness/issue-3096-1.stderr new file mode 100644 index 00000000000..97c34755189 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-1.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: type `()` is non-empty + --> $DIR/issue-3096-1.rs:2:11 + | +LL | match () { } + | ^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-3096-2.rs b/src/test/ui/pattern/usefulness/issue-3096-2.rs new file mode 100644 index 00000000000..a26e425809f --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-2.rs @@ -0,0 +1,6 @@ +enum Bottom { } + +fn main() { + let x = &() as *const () as *const Bottom; + match x { } //~ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/issue-3096-2.stderr b/src/test/ui/pattern/usefulness/issue-3096-2.stderr new file mode 100644 index 00000000000..472d1a91e6a --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-2.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty + --> $DIR/issue-3096-2.rs:5:11 + | +LL | match x { } + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `*const Bottom` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-31221.rs b/src/test/ui/pattern/usefulness/issue-31221.rs new file mode 100644 index 00000000000..e03f1ec5bc2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31221.rs @@ -0,0 +1,34 @@ +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(non_snake_case)] +#![deny(unreachable_patterns)] + +#[derive(Clone, Copy)] +enum Enum { + Var1, + Var2, +} + +fn main() { + use Enum::*; + let s = Var1; + match s { + Var1 => (), + Var3 => (), + Var2 => (), + //~^ ERROR unreachable pattern + }; + match &s { + &Var1 => (), + &Var3 => (), + &Var2 => (), + //~^ ERROR unreachable pattern + }; + let t = (Var1, Var1); + match t { + (Var1, b) => (), + (c, d) => (), + anything => () + //~^ ERROR unreachable pattern + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-31221.stderr b/src/test/ui/pattern/usefulness/issue-31221.stderr new file mode 100644 index 00000000000..7d349144456 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31221.stderr @@ -0,0 +1,32 @@ +error: unreachable pattern + --> $DIR/issue-31221.rs:18:9 + | +LL | Var3 => (), + | ---- matches any value +LL | Var2 => (), + | ^^^^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/issue-31221.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/issue-31221.rs:24:9 + | +LL | &Var3 => (), + | ----- matches any value +LL | &Var2 => (), + | ^^^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/issue-31221.rs:31:9 + | +LL | (c, d) => (), + | ------ matches any value +LL | anything => () + | ^^^^^^^^ unreachable pattern + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/pattern/usefulness/issue-31561.rs b/src/test/ui/pattern/usefulness/issue-31561.rs new file mode 100644 index 00000000000..813b2409cc8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31561.rs @@ -0,0 +1,10 @@ +enum Thing { + Foo(u8), + Bar, + Baz +} + +fn main() { + let Thing::Foo(y) = Thing::Foo(1); + //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered +} diff --git a/src/test/ui/pattern/usefulness/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr new file mode 100644 index 00000000000..2f562b23692 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31561.stderr @@ -0,0 +1,26 @@ +error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered + --> $DIR/issue-31561.rs:8:9 + | +LL | / enum Thing { +LL | | Foo(u8), +LL | | Bar, + | | --- not covered +LL | | Baz + | | --- not covered +LL | | } + | |_- `Thing` defined here +... +LL | let Thing::Foo(y) = Thing::Foo(1); + | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `Thing` +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/pattern/usefulness/issue-3601.rs b/src/test/ui/pattern/usefulness/issue-3601.rs new file mode 100644 index 00000000000..e33359beccd --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3601.rs @@ -0,0 +1,34 @@ +#![feature(box_patterns)] +#![feature(box_syntax)] + +struct HTMLImageData { + image: Option +} + +struct ElementData { + kind: Box +} + +enum ElementKind { + HTMLImageElement(HTMLImageData) +} + +enum NodeKind { + Element(ElementData) +} + +struct NodeData { + kind: Box, +} + +fn main() { + let mut id = HTMLImageData { image: None }; + let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) }; + let n = NodeData {kind : box NodeKind::Element(ed)}; + // n.b. span could be better + match n.kind { + box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns + box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true } + }, + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-3601.stderr b/src/test/ui/pattern/usefulness/issue-3601.stderr new file mode 100644 index 00000000000..c873c20cca8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3601.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered + --> $DIR/issue-3601.rs:30:44 + | +LL | box NodeKind::Element(ed) => match ed.kind { + | ^^^^^^^ pattern `Box(_, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Box` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-39362.rs b/src/test/ui/pattern/usefulness/issue-39362.rs new file mode 100644 index 00000000000..ea3c8f88e0b --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-39362.rs @@ -0,0 +1,18 @@ +enum Foo { + Bar { bar: Bar, id: usize } +} + +enum Bar { + A, B, C, D, E, F +} + +fn test(f: Foo) { + match f { + //~^ ERROR non-exhaustive patterns + //~| patterns + Foo::Bar { bar: Bar::A, .. } => (), + Foo::Bar { bar: Bar::B, .. } => (), + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-39362.stderr b/src/test/ui/pattern/usefulness/issue-39362.stderr new file mode 100644 index 00000000000..8c162e55619 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-39362.stderr @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered + --> $DIR/issue-39362.rs:10:11 + | +LL | / enum Foo { +LL | | Bar { bar: Bar, id: usize } +LL | | } + | |_- `Foo` defined here +... +LL | match f { + | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-40221.rs b/src/test/ui/pattern/usefulness/issue-40221.rs new file mode 100644 index 00000000000..e1f7e975b80 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-40221.rs @@ -0,0 +1,16 @@ +enum P { + C(PC), +} + +enum PC { + Q, + QA, +} + +fn test(proto: P) { + match proto { //~ ERROR non-exhaustive patterns + P::C(PC::Q) => (), + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-40221.stderr b/src/test/ui/pattern/usefulness/issue-40221.stderr new file mode 100644 index 00000000000..98efe805a0b --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-40221.stderr @@ -0,0 +1,18 @@ +error[E0004]: non-exhaustive patterns: `C(QA)` not covered + --> $DIR/issue-40221.rs:11:11 + | +LL | / enum P { +LL | | C(PC), + | | - not covered +LL | | } + | |_- `P` defined here +... +LL | match proto { + | ^^^^^ pattern `C(QA)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `P` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-4321.rs b/src/test/ui/pattern/usefulness/issue-4321.rs new file mode 100644 index 00000000000..9715f2eba2f --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-4321.rs @@ -0,0 +1,8 @@ +fn main() { + let tup = (true, true); + println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered + (false, false) => "foo", + (false, true) => "bar", + (true, true) => "baz" + }); +} diff --git a/src/test/ui/pattern/usefulness/issue-4321.stderr b/src/test/ui/pattern/usefulness/issue-4321.stderr new file mode 100644 index 00000000000..1e8852556b1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-4321.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: `(true, false)` not covered + --> $DIR/issue-4321.rs:3:31 + | +LL | println!("foo {:}", match tup { + | ^^^ pattern `(true, false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(bool, bool)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-43253.rs b/src/test/ui/pattern/usefulness/issue-43253.rs deleted file mode 100644 index 349ba11a7cd..00000000000 --- a/src/test/ui/pattern/usefulness/issue-43253.rs +++ /dev/null @@ -1,47 +0,0 @@ -// check-pass -#![feature(exclusive_range_pattern)] -#![warn(unreachable_patterns)] -#![warn(overlapping_patterns)] - -fn main() { - // These cases should generate no warning. - match 10 { - 1..10 => {}, - 10 => {}, - _ => {}, - } - - match 10 { - 1..10 => {}, - 9..=10 => {}, //~ WARNING multiple patterns covering the same range - _ => {}, - } - - match 10 { - 1..10 => {}, - 10..=10 => {}, - _ => {}, - } - - // These cases should generate "unreachable pattern" warnings. - match 10 { - 1..10 => {}, - 9 => {}, //~ WARNING unreachable pattern - _ => {}, - } - - match 10 { - 1..10 => {}, - 8..=9 => {}, //~ WARNING unreachable pattern - _ => {}, - } - - match 10 { - 5..7 => {}, - 6 => {}, //~ WARNING unreachable pattern - 1..10 => {}, - 9..=9 => {}, //~ WARNING unreachable pattern - 6 => {}, //~ WARNING unreachable pattern - _ => {}, - } -} diff --git a/src/test/ui/pattern/usefulness/issue-43253.stderr b/src/test/ui/pattern/usefulness/issue-43253.stderr deleted file mode 100644 index 04feef1706c..00000000000 --- a/src/test/ui/pattern/usefulness/issue-43253.stderr +++ /dev/null @@ -1,52 +0,0 @@ -warning: multiple patterns covering the same range - --> $DIR/issue-43253.rs:16:9 - | -LL | 1..10 => {}, - | ----- this range overlaps on `9_i32` -LL | 9..=10 => {}, - | ^^^^^^ overlapping patterns - | -note: the lint level is defined here - --> $DIR/issue-43253.rs:4:9 - | -LL | #![warn(overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:29:9 - | -LL | 9 => {}, - | ^ - | -note: the lint level is defined here - --> $DIR/issue-43253.rs:3:9 - | -LL | #![warn(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:35:9 - | -LL | 8..=9 => {}, - | ^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:41:9 - | -LL | 6 => {}, - | ^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:43:9 - | -LL | 9..=9 => {}, - | ^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:44:9 - | -LL | 6 => {}, - | ^ - -warning: 6 warnings emitted - diff --git a/src/test/ui/pattern/usefulness/issue-50900.rs b/src/test/ui/pattern/usefulness/issue-50900.rs new file mode 100644 index 00000000000..27135af9575 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-50900.rs @@ -0,0 +1,19 @@ +#[derive(PartialEq, Eq)] +pub struct Tag(pub Context, pub u16); + +#[derive(PartialEq, Eq)] +pub enum Context { + Tiff, + Exif, +} + +impl Tag { + const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665); +} + +fn main() { + match Tag::ExifIFDPointer { + //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered + Tag::ExifIFDPointer => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-50900.stderr b/src/test/ui/pattern/usefulness/issue-50900.stderr new file mode 100644 index 00000000000..d378b6e8efe --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-50900.stderr @@ -0,0 +1,15 @@ +error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered + --> $DIR/issue-50900.rs:15:11 + | +LL | pub struct Tag(pub Context, pub u16); + | ------------------------------------- `Tag` defined here +... +LL | match Tag::ExifIFDPointer { + | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Tag` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-57472.rs b/src/test/ui/pattern/usefulness/issue-57472.rs new file mode 100644 index 00000000000..1131006374c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-57472.rs @@ -0,0 +1,35 @@ +#![crate_type="lib"] +#![deny(unreachable_patterns)] + +mod test_struct { + // Test the exact copy of the minimal example + // posted in the issue. + pub struct Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_], .. } => println!("foo"), + Punned { bar: [_], .. } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} + +mod test_union { + // Test the same thing using a union. + pub union Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_] } => println!("foo"), + Punned { bar: [_] } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} diff --git a/src/test/ui/pattern/usefulness/issue-57472.stderr b/src/test/ui/pattern/usefulness/issue-57472.stderr new file mode 100644 index 00000000000..26efdf6dbaf --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-57472.stderr @@ -0,0 +1,20 @@ +error: unreachable pattern + --> $DIR/issue-57472.rs:15:13 + | +LL | Punned { bar: [_], .. } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-57472.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/issue-57472.rs:31:13 + | +LL | Punned { bar: [_] } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/usefulness/issue-66501.rs b/src/test/ui/pattern/usefulness/issue-66501.rs new file mode 100644 index 00000000000..ffcfd4ad83e --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-66501.rs @@ -0,0 +1,12 @@ +// check-pass + +#![allow(unreachable_patterns)] + +fn main() { + const CONST: &[Option<()>; 1] = &[Some(())]; + match &[Some(())] { + &[None] => {} + CONST => {} + &[Some(())] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/match-range-fail-dominate.rs b/src/test/ui/pattern/usefulness/match-range-fail-dominate.rs deleted file mode 100644 index 37c4ccda0f5..00000000000 --- a/src/test/ui/pattern/usefulness/match-range-fail-dominate.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![deny(unreachable_patterns, overlapping_patterns)] - -fn main() { - match 5 { - 1 ..= 10 => { } - 5 ..= 6 => { } - //~^ ERROR unreachable pattern - _ => {} - }; - - match 5 { - 3 ..= 6 => { } - 4 ..= 6 => { } - //~^ ERROR unreachable pattern - _ => {} - }; - - match 5 { - 4 ..= 6 => { } - 4 ..= 6 => { } - //~^ ERROR unreachable pattern - _ => {} - }; - - match 'c' { - 'A' ..= 'z' => {} - 'a' ..= 'z' => {} - //~^ ERROR unreachable pattern - _ => {} - }; - - match 1.0f64 { - 0.01f64 ..= 6.5f64 => {} - //~^ WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - 0.02f64 => {} //~ ERROR unreachable pattern - //~^ WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - _ => {} - }; -} diff --git a/src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr b/src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr deleted file mode 100644 index 6922170fccb..00000000000 --- a/src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr +++ /dev/null @@ -1,93 +0,0 @@ -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:6:7 - | -LL | 5 ..= 6 => { } - | ^^^^^^^ - | -note: the lint level is defined here - --> $DIR/match-range-fail-dominate.rs:1:9 - | -LL | #![deny(unreachable_patterns, overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:13:7 - | -LL | 4 ..= 6 => { } - | ^^^^^^^ - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:20:7 - | -LL | 4 ..= 6 => { } - | ^^^^^^^ - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:27:7 - | -LL | 'a' ..= 'z' => {} - | ^^^^^^^^^^^ - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:7 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^^ - | - = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:19 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:42:7 - | -LL | 0.02f64 => {} - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:42:7 - | -LL | 0.02f64 => {} - | ^^^^^^^ - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:7 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:19 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:42:7 - | -LL | 0.02f64 => {} - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: aborting due to 5 previous errors; 6 warnings emitted - diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.rs deleted file mode 100644 index 588fecbf10d..00000000000 --- a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![allow(illegal_floating_point_literal_pattern)] -#![deny(unreachable_patterns)] - -fn main() { - match 0.0 { - 0.0..=1.0 => {} - _ => {} // ok - } - - match 0.0 { //~ ERROR non-exhaustive patterns - 0.0..=1.0 => {} - } -} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr deleted file mode 100644 index 4835fa86cc0..00000000000 --- a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-float-range-match.rs:10:11 - | -LL | match 0.0 { - | ^^^ pattern `_` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `f64` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs deleted file mode 100644 index 0c52876e21f..00000000000 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::{usize, isize}; - -fn main() { - match 0usize { - //~^ ERROR non-exhaustive patterns - //~| NOTE pattern `_` not covered - //~| NOTE the matched value is of type `usize` - //~| NOTE `usize` does not have a fixed maximum value - 0 ..= usize::MAX => {} - } - - match 0isize { - //~^ ERROR non-exhaustive patterns - //~| NOTE pattern `_` not covered - //~| NOTE the matched value is of type `isize` - //~| NOTE `isize` does not have a fixed maximum value - isize::MIN ..= isize::MAX => {} - } - - match 7usize {} - //~^ ERROR non-exhaustive patterns - //~| NOTE the matched value is of type `usize` -} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr deleted file mode 100644 index d0aa452fd38..00000000000 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:4:11 - | -LL | match 0usize { - | ^^^^^^ pattern `_` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching - -error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:12:11 - | -LL | match 0isize { - | ^^^^^^ pattern `_` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `isize` - = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching - -error[E0004]: non-exhaustive patterns: type `usize` is non-empty - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:20:11 - | -LL | match 7usize {} - | ^^^^^^ - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `usize` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs new file mode 100644 index 00000000000..cb44c1da76b --- /dev/null +++ b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs @@ -0,0 +1,36 @@ +#[deny(unreachable_patterns)] + +fn parse_data1(data: &[u8]) -> u32 { + match data { + b"" => 1, + _ => 2, + } +} + +fn parse_data2(data: &[u8]) -> u32 { + match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered + b"" => 1, + } +} + +fn parse_data3(data: &[u8; 0]) -> u8 { + match data { + b"" => 1, + } +} + +fn parse_data4(data: &[u8]) -> u8 { + match data { //~ ERROR non-exhaustive patterns + b"aaa" => 0, + [_, _, _] => 1, + } +} + +fn parse_data5(data: &[u8; 3]) -> u8 { + match data { + b"aaa" => 0, + [_, _, _] => 1, + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr new file mode 100644 index 00000000000..6ce53a4f21e --- /dev/null +++ b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered + --> $DIR/type_polymorphic_byte_str_literals.rs:11:11 + | +LL | match data { + | ^^^^ pattern `&[_, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[u8]` + +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered + --> $DIR/type_polymorphic_byte_str_literals.rs:23:11 + | +LL | match data { + | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[u8]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs deleted file mode 100644 index 54aeb8616d9..00000000000 --- a/src/test/ui/precise_pointer_size_matching.rs +++ /dev/null @@ -1,33 +0,0 @@ -// normalize-stderr-32bit: "-2147483648isize" -> "$$ISIZE_MIN" -// normalize-stderr-64bit: "-9223372036854775808isize" -> "$$ISIZE_MIN" -// normalize-stderr-32bit: "2147483647isize" -> "$$ISIZE_MAX" -// normalize-stderr-64bit: "9223372036854775807isize" -> "$$ISIZE_MAX" -// normalize-stderr-32bit: "4294967295usize" -> "$$USIZE_MAX" -// normalize-stderr-64bit: "18446744073709551615usize" -> "$$USIZE_MAX" - -#![feature(precise_pointer_size_matching)] -#![feature(exclusive_range_pattern)] - -#![deny(unreachable_patterns, overlapping_patterns)] - -use std::{usize, isize}; - -fn main() { - match 0isize { - isize::MIN ..= isize::MAX => {} // ok - } - - match 0usize { - 0 ..= usize::MAX => {} // ok - } - - match 0isize { //~ ERROR non-exhaustive patterns - 1 ..= 8 => {} - -5 ..= 20 => {} - } - - match 0usize { //~ ERROR non-exhaustive patterns - 1 ..= 8 => {} - 5 ..= 20 => {} - } -} diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr deleted file mode 100644 index 9a34171a391..00000000000 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0004]: non-exhaustive patterns: `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered - --> $DIR/precise_pointer_size_matching.rs:24:11 - | -LL | match 0isize { - | ^^^^^^ patterns `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `isize` - -error[E0004]: non-exhaustive patterns: `0_usize` and `21_usize..=usize::MAX` not covered - --> $DIR/precise_pointer_size_matching.rs:29:11 - | -LL | match 0usize { - | ^^^^^^ patterns `0_usize` and `21_usize..=usize::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `usize` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0004`.