From 13d5e6d016f7ee2653f567bf219ec87db893e733 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Fri, 21 Aug 2020 21:56:40 +0200
Subject: [PATCH 1/8] Add Iterator::intersperse

---
 library/core/src/iter/adapters/intersperse.rs | 62 +++++++++++++++++++
 library/core/src/iter/adapters/mod.rs         |  3 +
 library/core/src/iter/mod.rs                  |  3 +-
 library/core/src/iter/traits/iterator.rs      | 24 ++++++-
 src/librustdoc/clean/utils.rs                 |  1 -
 src/librustdoc/lib.rs                         |  1 +
 6 files changed, 91 insertions(+), 3 deletions(-)
 create mode 100644 library/core/src/iter/adapters/intersperse.rs

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
new file mode 100644
index 0000000000000..d973ece34fbfa
--- /dev/null
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -0,0 +1,62 @@
+use crate::iter::Fuse;
+
+/// An iterator adapter that places a separator between all elements.
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")]
+#[derive(Debug, Clone)]
+pub struct Intersperse<I: Iterator>
+where
+    I::Item: Clone,
+{
+    element: I::Item,
+    iter: Fuse<I>,
+    peek: Option<I::Item>,
+}
+
+impl<I: Iterator> Intersperse<I>
+where
+    I::Item: Clone,
+{
+    pub(in super::super) fn new(iter: I, separator: I::Item) -> Self {
+        let mut iter = iter.fuse();
+        Self { peek: iter.next(), iter, element: separator }
+    }
+}
+
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")]
+impl<I> Iterator for Intersperse<I>
+where
+    I: Iterator,
+    I::Item: Clone,
+{
+    type Item = I::Item;
+
+    #[inline]
+    fn next(&mut self) -> Option<I::Item> {
+        if self.peek.is_some() {
+            self.peek.take()
+        } else {
+            self.peek = self.iter.next();
+            if self.peek.is_some() { Some(self.element.clone()) } else { None }
+        }
+    }
+
+    fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let mut accum = init;
+
+        if let Some(x) = self.peek.take() {
+            accum = f(accum, x);
+        }
+
+        let element = &self.element;
+
+        self.iter.fold(accum, |accum, x| {
+            let accum = f(accum, element.clone());
+            let accum = f(accum, x);
+            accum
+        })
+    }
+}
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index ab27fe15a8e2c..1a66769f02505 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -11,12 +11,15 @@ use super::{
 mod chain;
 mod flatten;
 mod fuse;
+mod intersperse;
 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;
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")]
+pub use self::intersperse::Intersperse;
 use self::zip::try_get_unchecked;
 #[unstable(feature = "trusted_random_access", issue = "none")]
 pub use self::zip::TrustedRandomAccess;
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 59f333e888b88..bf44c35ecc2b5 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -351,7 +351,8 @@ pub use self::adapters::Cloned;
 pub use self::adapters::Copied;
 #[stable(feature = "iterator_flatten", since = "1.29.0")]
 pub use self::adapters::Flatten;
-
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")]
+pub use self::adapters::Intersperse;
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
 pub use self::adapters::MapWhile;
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index b8a09f822b6da..051923e881e1b 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -8,7 +8,7 @@ use crate::ops::{Add, ControlFlow, Try};
 use super::super::TrustedRandomAccess;
 use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
 use super::super::{FlatMap, Flatten};
-use super::super::{FromIterator, Product, Sum, Zip};
+use super::super::{FromIterator, Intersperse, Product, Sum, Zip};
 use super::super::{
     Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
 };
@@ -536,6 +536,28 @@ pub trait Iterator {
         Zip::new(self, other.into_iter())
     }
 
+    /// Places a copy of `separator` between all elements.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_intersperse)]
+    ///
+    /// let hello = ["Hello", "World"].iter().map(|s| *s).intersperse(" ").collect::<String>();
+    /// assert_eq!(hello, "Hello World");
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")]
+    fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
+    where
+        Self: Sized,
+        Self::Item: Clone,
+    {
+        Intersperse::new(self, separator)
+    }
+
     /// Takes a closure and creates an iterator which calls that closure on each
     /// element.
     ///
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c577b771d6094..f3e169fe20e2a 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -8,7 +8,6 @@ use crate::clean::{
 };
 use crate::core::DocContext;
 
-use itertools::Itertools;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 73a783d54060c..d5459c5cd0344 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -12,6 +12,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
 #![feature(once_cell)]
+#![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 
 #[macro_use]

From 8a05fbc3619d8d87d2d35a4a97ef4ac19ac6852d Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 22 Aug 2020 16:55:37 +0200
Subject: [PATCH 2/8] Update library/core/src/iter/adapters/intersperse.rs

Co-authored-by: Ivan Tham <pickfire@riseup.net>
---
 library/core/src/iter/adapters/intersperse.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index d973ece34fbfa..48c785dfb5498 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -32,11 +32,11 @@ where
 
     #[inline]
     fn next(&mut self) -> Option<I::Item> {
-        if self.peek.is_some() {
-            self.peek.take()
+        if let Some(item) = self.peek.take() {
+            Some(item)
         } else {
-            self.peek = self.iter.next();
-            if self.peek.is_some() { Some(self.element.clone()) } else { None }
+            self.peek = Some(self.iter.next()?);
+            Some(self.element.clone())
         }
     }
 

From f470155998fc1f6a69a0c1b02f43acf789596ab1 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 22 Aug 2020 19:00:36 +0200
Subject: [PATCH 3/8] Address review comments

---
 library/core/src/iter/adapters/intersperse.rs | 2 +-
 library/core/src/iter/traits/iterator.rs      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index 48c785dfb5498..de8ff72522537 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -16,7 +16,7 @@ impl<I: Iterator> Intersperse<I>
 where
     I::Item: Clone,
 {
-    pub(in super::super) fn new(iter: I, separator: I::Item) -> Self {
+    pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
         let mut iter = iter.fuse();
         Self { peek: iter.next(), iter, element: separator }
     }
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 051923e881e1b..3a3687f577bec 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -545,7 +545,7 @@ pub trait Iterator {
     /// ```
     /// #![feature(iter_intersperse)]
     ///
-    /// let hello = ["Hello", "World"].iter().map(|s| *s).intersperse(" ").collect::<String>();
+    /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::<String>();
     /// assert_eq!(hello, "Hello World");
     /// ```
     #[inline]

From 97039d81a71cb1722571eb50a5c3dc63b5fd36a6 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 22 Aug 2020 19:33:12 +0200
Subject: [PATCH 4/8] Implement `size_hint`

---
 library/core/src/iter/adapters/intersperse.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index de8ff72522537..748da0b8f3e1d 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -59,4 +59,14 @@ where
             accum
         })
     }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        // We'll yield the whole `self.iter`, and just as many separators, as well as (if present)
+        // `self.peek`.
+        let (lo, hi) = self.iter.size_hint();
+        let has_peek = self.peek.is_some() as usize;
+        let lo = lo.saturating_add(lo).saturating_add(has_peek);
+        let hi = hi.map(|hi| hi.saturating_add(hi).saturating_add(has_peek));
+        (lo, hi)
+    }
 }

From 572b795a7bf9ea3e45c339e4a46c34057b13abb7 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Mon, 24 Aug 2020 23:32:04 +0200
Subject: [PATCH 5/8] Update library/core/src/iter/adapters/intersperse.rs

Co-authored-by: Oliver Middleton <olliemail27@gmail.com>
---
 library/core/src/iter/adapters/intersperse.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index 748da0b8f3e1d..52ffb5ab59182 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -66,7 +66,7 @@ where
         let (lo, hi) = self.iter.size_hint();
         let has_peek = self.peek.is_some() as usize;
         let lo = lo.saturating_add(lo).saturating_add(has_peek);
-        let hi = hi.map(|hi| hi.saturating_add(hi).saturating_add(has_peek));
+        let hi = hi.and_then(|hi| hi.checked_add(hi)).and_then(|hi| hi.checked_add(has_peek));
         (lo, hi)
     }
 }

From 00ad5c8b36fcf597f27b728e10befce6a45bd230 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sun, 6 Sep 2020 15:56:41 +0200
Subject: [PATCH 6/8] Rewrite and add tests, address remaining comments

---
 library/core/src/iter/adapters/intersperse.rs | 71 +++++++++++++------
 library/core/tests/iter.rs                    | 36 ++++++++++
 library/core/tests/lib.rs                     |  1 +
 3 files changed, 87 insertions(+), 21 deletions(-)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index 52ffb5ab59182..5d97dec140304 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -1,4 +1,6 @@
-use crate::iter::Fuse;
+use crate::ops::Try;
+
+use super::Peekable;
 
 /// An iterator adapter that places a separator between all elements.
 #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")]
@@ -7,9 +9,9 @@ pub struct Intersperse<I: Iterator>
 where
     I::Item: Clone,
 {
-    element: I::Item,
-    iter: Fuse<I>,
-    peek: Option<I::Item>,
+    separator: I::Item,
+    iter: Peekable<I>,
+    needs_sep: bool,
 }
 
 impl<I: Iterator> Intersperse<I>
@@ -17,8 +19,7 @@ where
     I::Item: Clone,
 {
     pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
-        let mut iter = iter.fuse();
-        Self { peek: iter.next(), iter, element: separator }
+        Self { iter: iter.peekable(), separator, needs_sep: false }
     }
 }
 
@@ -32,11 +33,12 @@ where
 
     #[inline]
     fn next(&mut self) -> Option<I::Item> {
-        if let Some(item) = self.peek.take() {
-            Some(item)
+        if self.needs_sep && self.iter.peek().is_some() {
+            self.needs_sep = false;
+            Some(self.separator.clone())
         } else {
-            self.peek = Some(self.iter.next()?);
-            Some(self.element.clone())
+            self.needs_sep = true;
+            self.iter.next()
         }
     }
 
@@ -47,26 +49,53 @@ where
     {
         let mut accum = init;
 
-        if let Some(x) = self.peek.take() {
-            accum = f(accum, x);
+        // Use `peek()` first to avoid calling `next()` on an empty iterator.
+        if !self.needs_sep || self.iter.peek().is_some() {
+            if let Some(x) = self.iter.next() {
+                accum = f(accum, x);
+            }
         }
 
-        let element = &self.element;
+        let element = &self.separator;
 
-        self.iter.fold(accum, |accum, x| {
-            let accum = f(accum, element.clone());
-            let accum = f(accum, x);
+        self.iter.fold(accum, |mut accum, x| {
+            accum = f(accum, element.clone());
+            accum = f(accum, x);
             accum
         })
     }
 
+    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Ok = B>,
+    {
+        let mut accum = init;
+
+        // Use `peek()` first to avoid calling `next()` on an empty iterator.
+        if !self.needs_sep || self.iter.peek().is_some() {
+            if let Some(x) = self.iter.next() {
+                accum = f(accum, x)?;
+            }
+        }
+
+        let element = &self.separator;
+
+        self.iter.try_fold(accum, |mut accum, x| {
+            accum = f(accum, element.clone())?;
+            accum = f(accum, x)?;
+            Try::from_ok(accum)
+        })
+    }
+
     fn size_hint(&self) -> (usize, Option<usize>) {
-        // We'll yield the whole `self.iter`, and just as many separators, as well as (if present)
-        // `self.peek`.
         let (lo, hi) = self.iter.size_hint();
-        let has_peek = self.peek.is_some() as usize;
-        let lo = lo.saturating_add(lo).saturating_add(has_peek);
-        let hi = hi.and_then(|hi| hi.checked_add(hi)).and_then(|hi| hi.checked_add(has_peek));
+        let next_is_elem = !self.needs_sep;
+        let lo = lo.saturating_add(lo).saturating_sub(next_is_elem as usize);
+        let hi = hi
+            .and_then(|hi| hi.checked_add(hi))
+            .and_then(|hi| hi.checked_sub(next_is_elem as usize));
         (lo, hi)
     }
 }
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 00e3972c42f9d..e96680f335ca7 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -3222,3 +3222,39 @@ fn test_flatten_non_fused_inner() {
     assert_eq!(iter.next(), Some(1));
     assert_eq!(iter.next(), None);
 }
+
+#[test]
+fn test_intersperse() {
+    let xs = ["a", "", "b", "c"];
+    let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
+    let text: String = v.concat();
+    assert_eq!(text, "a, , b, c".to_string());
+
+    let ys = [0, 1, 2, 3];
+    let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
+    assert!(it.next() == None);
+}
+
+#[test]
+fn test_intersperse_size_hint() {
+    let xs = ["a", "", "b", "c"];
+    let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
+    assert_eq!(iter.size_hint(), (7, Some(7)));
+
+    assert_eq!(iter.next(), Some("a"));
+    assert_eq!(iter.size_hint(), (6, Some(6)));
+    assert_eq!(iter.next(), Some(", "));
+    assert_eq!(iter.size_hint(), (5, Some(5)));
+}
+
+#[test]
+fn test_fold_specialization_intersperse() {
+    let mut iter = (1..2).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+    let mut iter = (1..3).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+    let mut iter = (1..4).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 4a651e5aa0ee3..e658c8ec411bb 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -33,6 +33,7 @@
 #![feature(int_error_matching)]
 #![feature(array_value_iter)]
 #![feature(iter_partition_in_place)]
+#![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
 #![feature(iter_order_by)]
 #![feature(cmp_min_max_by)]

From d3122a83239f2e2b21eeaf49950d51871e5c9c1c Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 12 Sep 2020 00:13:42 +0200
Subject: [PATCH 7/8] Remove incorrect `try_fold` and add more tests

---
 library/core/src/iter/adapters/intersperse.rs | 26 -----------
 library/core/tests/iter.rs                    | 44 +++++++++++++++++++
 2 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index 5d97dec140304..135759554a0ca 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -1,5 +1,3 @@
-use crate::ops::Try;
-
 use super::Peekable;
 
 /// An iterator adapter that places a separator between all elements.
@@ -65,30 +63,6 @@ where
         })
     }
 
-    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
-    where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
-    {
-        let mut accum = init;
-
-        // Use `peek()` first to avoid calling `next()` on an empty iterator.
-        if !self.needs_sep || self.iter.peek().is_some() {
-            if let Some(x) = self.iter.next() {
-                accum = f(accum, x)?;
-            }
-        }
-
-        let element = &self.separator;
-
-        self.iter.try_fold(accum, |mut accum, x| {
-            accum = f(accum, element.clone())?;
-            accum = f(accum, x)?;
-            Try::from_ok(accum)
-        })
-    }
-
     fn size_hint(&self) -> (usize, Option<usize>) {
         let (lo, hi) = self.iter.size_hint();
         let next_is_elem = !self.needs_sep;
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index e96680f335ca7..d79b9e171d756 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -3258,3 +3258,47 @@ fn test_fold_specialization_intersperse() {
     let mut iter = (1..4).intersperse(0);
     iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
 }
+
+#[test]
+fn test_try_fold_specialization_intersperse_ok() {
+    let mut iter = (1..2).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+
+    let mut iter = (1..3).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+
+    let mut iter = (1..4).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_err() {
+    let orig_iter = ["a", "b"].iter().copied().intersperse("-");
+
+    // Abort after the first item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|_| None::<()>);
+    assert_eq!(iter.next(), Some("-"));
+    assert_eq!(iter.next(), Some("b"));
+    assert_eq!(iter.next(), None);
+
+    // Abort after the second item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
+    assert_eq!(iter.next(), Some("b"));
+    assert_eq!(iter.next(), None);
+
+    // Abort after the third item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
+    assert_eq!(iter.next(), None);
+}

From 3a069a03f052f239cf3fa8b26ac69fce5f672bc5 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 12 Sep 2020 01:12:10 +0200
Subject: [PATCH 8/8] Improve `size_hint`

---
 library/core/src/iter/adapters/intersperse.rs | 9 +++++----
 library/core/tests/iter.rs                    | 2 ++
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index 135759554a0ca..4656a725a3c61 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -66,10 +66,11 @@ where
     fn size_hint(&self) -> (usize, Option<usize>) {
         let (lo, hi) = self.iter.size_hint();
         let next_is_elem = !self.needs_sep;
-        let lo = lo.saturating_add(lo).saturating_sub(next_is_elem as usize);
-        let hi = hi
-            .and_then(|hi| hi.checked_add(hi))
-            .and_then(|hi| hi.checked_sub(next_is_elem as usize));
+        let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
+        let hi = match hi {
+            Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
+            None => None,
+        };
         (lo, hi)
     }
 }
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index d79b9e171d756..07c1ebc85002d 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -3245,6 +3245,8 @@ fn test_intersperse_size_hint() {
     assert_eq!(iter.size_hint(), (6, Some(6)));
     assert_eq!(iter.next(), Some(", "));
     assert_eq!(iter.size_hint(), (5, Some(5)));
+
+    assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
 }
 
 #[test]