Skip to main content

rustc_hir_typeck/
diverges.rs

1use std::{cmp, ops};
2
3use rustc_span::{DUMMY_SP, 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]
impl ::core::clone::Clone for Diverges {
    #[inline]
    fn clone(&self) -> Diverges {
        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 {
            Diverges::Maybe => ::core::fmt::Formatter::write_str(f, "Maybe"),
            Diverges::Always { span: __self_0, custom_note: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Always", "span", __self_0, "custom_note", &__self_1),
            Diverges::WarnedAlways =>
                ::core::fmt::Formatter::write_str(f, "WarnedAlways"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for Diverges {
    #[inline]
    fn eq(&self, other: &Diverges) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Diverges::Always { span: __self_0, custom_note: __self_1 },
                    Diverges::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_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Span>;
        let _: ::core::cmp::AssertParamIsEq<Option<&'static str>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for Diverges {
    #[inline]
    fn partial_cmp(&self, other: &Diverges)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match (self, other) {
            (Diverges::Always { span: __self_0, custom_note: __self_1 },
                Diverges::Always { span: __arg1_0, custom_note: __arg1_1 }) =>
                match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0)
                    {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
                    cmp => cmp,
                },
            _ =>
                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
                    &__arg1_discr),
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Diverges {
    #[inline]
    fn cmp(&self, other: &Diverges) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
            ::core::cmp::Ordering::Equal =>
                match (self, other) {
                    (Diverges::Always { span: __self_0, custom_note: __self_1 },
                        Diverges::Always { span: __arg1_0, custom_note: __arg1_1 })
                        =>
                        match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
                            ::core::cmp::Ordering::Equal =>
                                ::core::cmp::Ord::cmp(__self_1, __arg1_1),
                            cmp => cmp,
                        },
                    _ => ::core::cmp::Ordering::Equal,
                },
            cmp => cmp,
        }
    }
}Ord)]
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        cmp::min(self, other)
44    }
45}
46
47impl ops::BitOr for Diverges {
48    type Output = Self;
49    fn bitor(self, other: Self) -> Self {
50        cmp::max(self, other)
51    }
52}
53
54impl ops::BitAndAssign for Diverges {
55    fn bitand_assign(&mut self, other: Self) {
56        *self = *self & other;
57    }
58}
59
60impl ops::BitOrAssign for Diverges {
61    fn bitor_assign(&mut self, other: Self) {
62        *self = *self | other;
63    }
64}
65
66impl Diverges {
67    /// Creates a `Diverges::Always` with the provided `span` and the default note message.
68    pub(super) fn always(span: Span) -> Diverges {
69        Diverges::Always { span, custom_note: None }
70    }
71
72    pub(super) fn is_always(self) -> bool {
73        // Enum comparison ignores the
74        // contents of fields, so we just
75        // fill them in with garbage here.
76        self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
77    }
78}