diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 9a589c1f3b55c..0ea2723f155ed 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,4 +1,4 @@ -use crate::ops::{ControlFlow, Try}; +use crate::ops::{ControlFlow, NeverShortCircuit, Try}; /// An iterator able to yield elements from both ends. /// @@ -292,16 +292,17 @@ pub trait DoubleEndedIterator: Iterator { #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] - fn rfold(mut self, init: B, mut f: F) -> B + fn rfold(mut self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - let mut accum = init; - while let Some(x) = self.next_back() { - accum = f(accum, x); + #[inline] + fn call(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> NeverShortCircuit { + move |accum, item| NeverShortCircuit(f(accum, item)) } - accum + + self.try_rfold(init, call(f)).0 } /// Searches for an element of an iterator from the back that satisfies a predicate. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d957a7527cf58..454062750c706 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,5 +1,5 @@ use crate::cmp::{self, Ordering}; -use crate::ops::{ControlFlow, Try}; +use crate::ops::{ControlFlow, NeverShortCircuit, Try}; use super::super::TrustedRandomAccessNoCoerce; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; @@ -2161,16 +2161,17 @@ pub trait Iterator { #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn fold(mut self, init: B, mut f: F) -> B + fn fold(mut self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - let mut accum = init; - while let Some(x) = self.next() { - accum = f(accum, x); + #[inline] + fn call(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> NeverShortCircuit { + move |accum, item| NeverShortCircuit(f(accum, item)) } - accum + + self.try_fold(init, call(f)).0 } /// Reduces the elements to a single one, by repeatedly applying a reducing diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index bd7feb8b183ce..284e0ab863fc3 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -184,6 +184,8 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::{FromResidual, Try}; +pub(crate) use self::try_trait::NeverShortCircuit; + #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 6bdcda775ee83..49403b389ea3e 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -338,3 +338,37 @@ pub trait FromResidual::Residual> { #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_residual(residual: R) -> Self; } + +/// An adapter for implementing non-try methods via the `Try` implementation. +/// +/// Conceptually the same as `Result`, but requiring less work in trait +/// solving and inhabited-ness checking and such, by being an obvious newtype +/// and not having `From` bounds lying around. +/// +/// Not currently planned to be exposed publicly, so just `pub(crate)`. +#[repr(transparent)] +pub(crate) struct NeverShortCircuit(pub T); + +pub(crate) enum NeverShortCircuitResidual {} + +impl Try for NeverShortCircuit { + type Output = T; + type Residual = NeverShortCircuitResidual; + + #[inline] + fn branch(self) -> ControlFlow { + ControlFlow::Continue(self.0) + } + + #[inline] + fn from_output(x: T) -> Self { + NeverShortCircuit(x) + } +} + +impl FromResidual for NeverShortCircuit { + #[inline] + fn from_residual(never: NeverShortCircuitResidual) -> Self { + match never {} + } +} diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr index b93aeade95e42..e3c43668d195b 100644 --- a/src/test/ui/issues/issue-3044.stderr +++ b/src/test/ui/issues/issue-3044.stderr @@ -11,7 +11,7 @@ LL | | }); note: associated function defined here --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn fold(mut self, init: B, mut f: F) -> B +LL | fn fold(mut self, init: B, f: F) -> B | ^^^^ error: aborting due to previous error