Skip to main content

rustc_hir_typeck/
diverges.rs

1use std::ops;
2
3use rustc_span::Span;
4
5/// Tracks whether executing a node may exit normally (versus
6/// return/break/panic, which "diverge", leaving dead code in their
7/// wake). Tracked semi-automatically (through type variables marked
8/// as diverging), with some manual adjustments for control-flow
9/// primitives (approximating a CFG).
10#[derive(#[automatically_derived]
impl ::core::marker::Copy for Diverges { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Diverges { }
#[automatically_derived]
impl ::core::clone::Clone for Diverges {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<Span>;
        let _: ::core::clone::AssertParamIsClone<Option<&'static str>>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Diverges {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Maybe => ::core::fmt::Formatter::write_str(f, "Maybe"),
            Self::Always { span: __self_0, custom_note: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Always", "span", __self_0, "custom_note", &__self_1),
            Self::WarnedAlways =>
                ::core::fmt::Formatter::write_str(f, "WarnedAlways"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Diverges { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Diverges {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
                ::core::intrinsics::discriminant_value(other) &&
            match (self, other) {
                (Self::Always { span: __self_0, custom_note: __self_1 },
                    Self::Always { span: __arg1_0, custom_note: __arg1_1 }) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Diverges {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Span>;
        let _: ::core::cmp::AssertParamIsEq<Option<&'static str>>;
    }
}Eq)]
11pub(crate) enum Diverges {
12    /// Potentially unknown, some cases converge,
13    /// others require a CFG to determine them.
14    Maybe,
15
16    /// Definitely known to diverge and therefore
17    /// not reach the next sibling or its parent.
18    Always {
19        /// The `Span` points to the expression
20        /// that caused us to diverge
21        /// (e.g. `return`, `break`, etc).
22        span: Span,
23        /// In some cases (e.g. a `match` expression
24        /// where all arms diverge), we may be
25        /// able to provide a more informative
26        /// message to the user.
27        /// If this is `None`, a default message
28        /// will be generated, which is suitable
29        /// for most cases.
30        custom_note: Option<&'static str>,
31    },
32
33    /// Same as `Always` but with a reachability
34    /// warning already emitted.
35    WarnedAlways,
36}
37
38// Convenience impls for combining `Diverges`.
39
40impl ops::BitAnd for Diverges {
41    type Output = Self;
42    fn bitand(self, other: Self) -> Self {
43        match (self, other) {
44            (x @ Self::Maybe, _) => x,
45            (_, x @ Self::Maybe) => x,
46            // Using `span`/`custom_note` from `self` seems to give better error messages.
47            (x @ Self::Always { .. }, Self::Always { .. }) => x,
48            (Self::WarnedAlways, x) => x,
49            (x, Self::WarnedAlways) => x,
50        }
51    }
52}
53
54impl ops::BitOr for Diverges {
55    type Output = Self;
56    fn bitor(self, other: Self) -> Self {
57        match (self, other) {
58            (x @ Self::WarnedAlways, _) => x,
59            (_, x @ Self::WarnedAlways) => x,
60            // Using `span`/`custom_note` from `self` seems to give better error messages.
61            (x @ Self::Always { .. }, Self::Always { .. }) => x,
62            (Self::Maybe, x) => x,
63            (x, Self::Maybe) => x,
64        }
65    }
66}
67
68impl ops::BitAndAssign for Diverges {
69    fn bitand_assign(&mut self, other: Self) {
70        *self = *self & other;
71    }
72}
73
74impl ops::BitOrAssign for Diverges {
75    fn bitor_assign(&mut self, other: Self) {
76        *self = *self | other;
77    }
78}
79
80impl Diverges {
81    /// Creates a `Diverges::Always` with the provided `span` and the default note message.
82    pub(super) fn always(span: Span) -> Diverges {
83        Diverges::Always { span, custom_note: None }
84    }
85
86    pub(super) fn is_always(self) -> bool {
87        #[allow(non_exhaustive_omitted_patterns)] match self {
    Diverges::WarnedAlways | Diverges::Always { .. } => true,
    _ => false,
}matches!(self, Diverges::WarnedAlways | Diverges::Always { .. })
88    }
89}