From fac272688e9d561b1fff71621323682d23e4c31d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Sep 2020 00:59:41 -0700 Subject: [PATCH 1/2] Use ops::ControlFlow in graph::iterate --- .../rustc_data_structures/src/graph/iterate/mod.rs | 13 +++++-------- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_mir_build/src/lib.rs | 1 + compiler/rustc_mir_build/src/lints.rs | 6 +++--- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/traits/double_ended.rs | 2 +- library/core/src/ops/control_flow.rs | 7 +++++++ 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 64ff6130ddffb..8946666d96142 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -87,11 +87,8 @@ where } /// Allows searches to terminate early with a value. -#[derive(Clone, Copy, Debug)] -pub enum ControlFlow { - Break(T), - Continue, -} +// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`. +pub type ControlFlow = std::ops::ControlFlow<(), T>; /// The status of a node in the depth-first search. /// @@ -260,12 +257,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Behave as if no edges exist from `source` to `target`. @@ -290,7 +287,7 @@ where ) -> ControlFlow { match prior_status { Some(NodeStatus::Visited) => ControlFlow::Break(()), - _ => ControlFlow::Continue, + _ => ControlFlow::CONTINUE, } } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index de4e7a1342431..88c160e93b66a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(incomplete_features)] +#![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] #![feature(generators)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 313bb979a5161..e55180ff4be52 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -6,6 +6,7 @@ #![feature(box_syntax)] #![feature(const_fn)] #![feature(const_panic)] +#![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] #![feature(or_patterns)] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index fd2d5a4abd424..b85ada15ed51c 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -117,7 +117,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::Continue + ControlFlow::CONTINUE } else { ControlFlow::Break(NonRecursive) } @@ -131,7 +131,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue, + | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, } } @@ -144,7 +144,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { } } - ControlFlow::Continue + ControlFlow::CONTINUE } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index c3f1269401aa9..d89874eb7a913 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1273,7 +1273,7 @@ where ) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::Continue(()), + None => ControlFlow::CONTINUE, } } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index f50807116bd09..a025bc8b56049 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -310,7 +310,7 @@ pub trait DoubleEndedIterator: Iterator { mut predicate: impl FnMut(&T) -> bool, ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 687d423dcb635..3f0cce4e18ac9 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -65,3 +65,10 @@ impl ControlFlow { } } } + +impl ControlFlow<(), B> { + /// It's frequently the case that there's no value needed with `Continue`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const CONTINUE: Self = ControlFlow::Continue(()); +} From 59e37332b0d2d0c5e43bea1184ec0387fb07cc80 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Sep 2020 16:28:23 -0700 Subject: [PATCH 2/2] Add `BREAK` too, and improve the comments --- .../src/graph/iterate/mod.rs | 2 +- library/core/src/iter/traits/iterator.rs | 14 ++++---- library/core/src/ops/control_flow.rs | 36 +++++++++++++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 8946666d96142..bc3d1ce53bac5 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -286,7 +286,7 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::Break(()), + Some(NodeStatus::Visited) => ControlFlow::BREAK, _ => ControlFlow::CONTINUE, } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 46ef12cd938b3..ceeae2371e130 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2086,10 +2086,10 @@ pub trait Iterator { #[inline] fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } } - self.try_fold((), check(f)) == ControlFlow::Continue(()) + self.try_fold((), check(f)) == ControlFlow::CONTINUE } /// Tests if any element of the iterator matches a predicate. @@ -2139,11 +2139,11 @@ pub trait Iterator { #[inline] fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) } + if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } } - self.try_fold((), check(f)) == ControlFlow::Break(()) + self.try_fold((), check(f)) == ControlFlow::BREAK } /// Searches for an element of an iterator that satisfies a predicate. @@ -2201,7 +2201,7 @@ pub trait Iterator { mut predicate: impl FnMut(&T) -> bool, ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -2236,7 +2236,7 @@ pub trait Iterator { ) -> impl FnMut((), T) -> ControlFlow<(), B> { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::Continue(()), + None => ControlFlow::CONTINUE, } } @@ -2278,7 +2278,7 @@ pub trait Iterator { R: Try, { move |(), x| match f(&x).into_result() { - Ok(false) => ControlFlow::Continue(()), + Ok(false) => ControlFlow::CONTINUE, Ok(true) => ControlFlow::Break(Ok(x)), Err(x) => ControlFlow::Break(Err(x)), } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 3f0cce4e18ac9..b0c7dc1a51875 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -69,6 +69,42 @@ impl ControlFlow { impl ControlFlow<(), B> { /// It's frequently the case that there's no value needed with `Continue`, /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// let last_used = (1..10).chain(20..25).try_for_each(|x| { + /// partial_sum += x; + /// if partial_sum > 100 { ControlFlow::Break(x) } + /// else { ControlFlow::CONTINUE } + /// }); + /// assert_eq!(last_used.break_value(), Some(22)); + /// ``` #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub const CONTINUE: Self = ControlFlow::Continue(()); } + +impl ControlFlow { + /// APIs like `try_for_each` don't need values with `Break`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// (1..10).chain(20..25).try_for_each(|x| { + /// if partial_sum > 100 { ControlFlow::BREAK } + /// else { partial_sum += x; ControlFlow::CONTINUE } + /// }); + /// assert_eq!(partial_sum, 108); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const BREAK: Self = ControlFlow::Break(()); +}