1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 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 }
    }
}