mago-codex 1.47.3

PHP type system representation, comparison logic, and codebase metadata for static analysis.
Documentation
use mago_phpdoc_syntax::cst::TemplateTagValueVariance;
use mago_phpdoc_syntax::cst::r#type::GenericParameterVariance;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Variance {
    Invariant,
    Covariant,
    Contravariant,
    Bivariant,
}

impl From<GenericParameterVariance<'_>> for Variance {
    fn from(variance: GenericParameterVariance<'_>) -> Self {
        match variance {
            GenericParameterVariance::Covariant(_) => Variance::Covariant,
            GenericParameterVariance::Contravariant(_) => Variance::Contravariant,
        }
    }
}

impl From<TemplateTagValueVariance> for Variance {
    fn from(variance: TemplateTagValueVariance) -> Self {
        match variance {
            TemplateTagValueVariance::Invariant => Variance::Invariant,
            TemplateTagValueVariance::Covariant => Variance::Covariant,
            TemplateTagValueVariance::Contravariant => Variance::Contravariant,
        }
    }
}

impl Variance {
    #[inline]
    #[must_use]
    pub const fn is_invariant(&self) -> bool {
        matches!(self, Variance::Invariant)
    }

    #[inline]
    #[must_use]
    pub const fn is_covariant(&self) -> bool {
        matches!(self, Variance::Covariant)
    }

    #[inline]
    #[must_use]
    pub const fn is_bivariant(&self) -> bool {
        matches!(self, Variance::Bivariant)
    }

    #[inline]
    #[must_use]
    pub const fn flip(self) -> Self {
        match self {
            Variance::Covariant => Variance::Contravariant,
            Variance::Contravariant => Variance::Covariant,
            other => other,
        }
    }

    #[inline]
    #[must_use]
    pub const fn is_readonly(&self) -> bool {
        matches!(self, Variance::Covariant | Variance::Invariant)
    }

    #[inline]
    #[must_use]
    pub const fn project(self, polarity: Variance) -> Option<bool> {
        let reads = matches!(self, Variance::Covariant | Variance::Invariant);
        let writes = matches!(self, Variance::Contravariant | Variance::Invariant);

        match polarity {
            Variance::Contravariant => {
                if writes {
                    Some(true)
                } else {
                    None
                }
            }
            _ => {
                if reads {
                    Some(true)
                } else {
                    Some(false)
                }
            }
        }
    }
}

impl std::fmt::Display for Variance {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Variance::Invariant => write!(f, "invariant"),
            Variance::Covariant => write!(f, "covariant"),
            Variance::Contravariant => write!(f, "contravariant"),
            Variance::Bivariant => write!(f, "*"),
        }
    }
}