summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_typeck/src/check/diverges.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_typeck/src/check/diverges.rs')
-rw-r--r--compiler/rustc_typeck/src/check/diverges.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_typeck/src/check/diverges.rs
new file mode 100644
index 000000000..963a93a95
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/diverges.rs
@@ -0,0 +1,78 @@
+use rustc_span::source_map::DUMMY_SP;
+use rustc_span::{self, Span};
+use std::{cmp, ops};
+
+/// Tracks whether executing a node may exit normally (versus
+/// return/break/panic, which "diverge", leaving dead code in their
+/// wake). Tracked semi-automatically (through type variables marked
+/// as diverging), with some manual adjustments for control-flow
+/// primitives (approximating a CFG).
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Diverges {
+ /// Potentially unknown, some cases converge,
+ /// others require a CFG to determine them.
+ Maybe,
+
+ /// Definitely known to diverge and therefore
+ /// not reach the next sibling or its parent.
+ Always {
+ /// The `Span` points to the expression
+ /// that caused us to diverge
+ /// (e.g. `return`, `break`, etc).
+ span: Span,
+ /// In some cases (e.g. a `match` expression
+ /// where all arms diverge), we may be
+ /// able to provide a more informative
+ /// message to the user.
+ /// If this is `None`, a default message
+ /// will be generated, which is suitable
+ /// for most cases.
+ custom_note: Option<&'static str>,
+ },
+
+ /// Same as `Always` but with a reachability
+ /// warning already emitted.
+ WarnedAlways,
+}
+
+// Convenience impls for combining `Diverges`.
+
+impl ops::BitAnd for Diverges {
+ type Output = Self;
+ fn bitand(self, other: Self) -> Self {
+ cmp::min(self, other)
+ }
+}
+
+impl ops::BitOr for Diverges {
+ type Output = Self;
+ fn bitor(self, other: Self) -> Self {
+ cmp::max(self, other)
+ }
+}
+
+impl ops::BitAndAssign for Diverges {
+ fn bitand_assign(&mut self, other: Self) {
+ *self = *self & other;
+ }
+}
+
+impl ops::BitOrAssign for Diverges {
+ fn bitor_assign(&mut self, other: Self) {
+ *self = *self | other;
+ }
+}
+
+impl Diverges {
+ /// Creates a `Diverges::Always` with the provided `span` and the default note message.
+ pub(super) fn always(span: Span) -> Diverges {
+ Diverges::Always { span, custom_note: None }
+ }
+
+ pub(super) fn is_always(self) -> bool {
+ // Enum comparison ignores the
+ // contents of fields, so we just
+ // fill them in with garbage here.
+ self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
+ }
+}