    module Language.C.Analysis.TypeConversions (
        arithmeticConversion,
        floatConversion,
        intConversion
    ) where

    import Language.C.Analysis.SemRep

    -- | For an arithmetic operator, if the arguments are of the given
    --   types, return the type of the full expression.
    arithmeticConversion :: TypeName -> TypeName -> Maybe TypeName
    -- XXX: I'm assuming that double `op` complex float = complex
    -- double. The standard seems somewhat unclear on whether this is
    -- really the case.
    arithmeticConversion :: TypeName -> TypeName -> Maybe TypeName
    arithmeticConversion (TyComplex FloatType
    t1) (TyComplex FloatType
    t2) =
      TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just (TypeName -> Maybe TypeName) -> TypeName -> Maybe TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> TypeName
    TyComplex (FloatType -> TypeName) -> FloatType -> TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> FloatType -> FloatType
    floatConversion FloatType
    t1 FloatType
    t2
    arithmeticConversion (TyComplex FloatType
    t1) (TyFloating FloatType
    t2) =
      TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just (TypeName -> Maybe TypeName) -> TypeName -> Maybe TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> TypeName
    TyComplex (FloatType -> TypeName) -> FloatType -> TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> FloatType -> FloatType
    floatConversion FloatType
    t1 FloatType
    t2
    arithmeticConversion (TyFloating FloatType
    t1) (TyComplex FloatType
    t2) =
      TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just (TypeName -> Maybe TypeName) -> TypeName -> Maybe TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> TypeName
    TyComplex (FloatType -> TypeName) -> FloatType -> TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> FloatType -> FloatType
    floatConversion FloatType
    t1 FloatType
    t2
    arithmeticConversion t1 :: TypeName
    t1@(TyComplex FloatType
    _) (TyIntegral IntType
    _) = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just TypeName
    t1
    arithmeticConversion (TyIntegral IntType
    _) t2 :: TypeName
    t2@(TyComplex FloatType
    _) = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just TypeName
    t2
    arithmeticConversion (TyFloating FloatType
    t1) (TyFloating FloatType
    t2) =
      TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just (TypeName -> Maybe TypeName) -> TypeName -> Maybe TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> TypeName
    TyFloating (FloatType -> TypeName) -> FloatType -> TypeName
    forall a b. (a -> b) -> a -> b
    $ FloatType -> FloatType -> FloatType
    floatConversion FloatType
    t1 FloatType
    t2
    arithmeticConversion t1 :: TypeName
    t1@(TyFloating FloatType
    _) (TyIntegral IntType
    _) = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just TypeName
    t1
    arithmeticConversion (TyIntegral IntType
    _) t2 :: TypeName
    t2@(TyFloating FloatType
    _) = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just TypeName
    t2
    arithmeticConversion (TyIntegral IntType
    t1) (TyIntegral IntType
    t2) =
      TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just (TypeName -> Maybe TypeName) -> TypeName -> Maybe TypeName
    forall a b. (a -> b) -> a -> b
    $ IntType -> TypeName
    TyIntegral (IntType -> TypeName) -> IntType -> TypeName
    forall a b. (a -> b) -> a -> b
    $ IntType -> IntType -> IntType
    intConversion IntType
    t1 IntType
    t2
    arithmeticConversion (TyEnum EnumTypeRef
    _) (TyEnum EnumTypeRef
    _) = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just (TypeName -> Maybe TypeName) -> TypeName -> Maybe TypeName
    forall a b. (a -> b) -> a -> b
    $ IntType -> TypeName
    TyIntegral IntType
    TyInt
    arithmeticConversion (TyEnum EnumTypeRef
    _) TypeName
    t2 = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just TypeName
    t2
    arithmeticConversion TypeName
    t1 (TyEnum EnumTypeRef
    _) = TypeName -> Maybe TypeName
    forall a. a -> Maybe a
    Just TypeName
    t1
    arithmeticConversion TypeName
    _ TypeName
    _ = Maybe TypeName
    forall a. Maybe a
    Nothing

    floatConversion :: FloatType -> FloatType -> FloatType
    floatConversion :: FloatType -> FloatType -> FloatType
    floatConversion = FloatType -> FloatType -> FloatType
    forall a. Ord a => a -> a -> a
    max

    intConversion :: IntType -> IntType -> IntType
    intConversion :: IntType -> IntType -> IntType
    intConversion IntType
    t1 IntType
    t2 = IntType -> IntType -> IntType
    forall a. Ord a => a -> a -> a
    max IntType
    TyInt (IntType -> IntType -> IntType
    forall a. Ord a => a -> a -> a
    max IntType
    t1 IntType
    t2)