    {-# LANGUAGE PatternSynonyms #-}

    module GHC.Types.SourceFile
       ( HscSource(HsBootFile, HsigFile, ..)
       , HsBootOrSig(..)
       , hscSourceToIsBoot
       , isHsBootOrSig
       , isHsBootFile, isHsigFile
       , hscSourceString
       )
    where

    import GHC.Prelude
    import GHC.Utils.Binary
    import GHC.Unit.Types

    {- Note [HscSource types]
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    There are three types of source file for Haskell code:

         * HsSrcFile is an ordinary hs file which contains code,

         * HsBootFile is an hs-boot file, which is used to break
           recursive module imports (there will always be an
           HsSrcFile associated with it), and

         * HsigFile is an hsig file, which contains only type
           signatures and is used to specify signatures for
           modules.

    Syntactically, hs-boot files and hsig files are quite similar: they
    only include type signatures and must be associated with an
    actual HsSrcFile.  isHsBootOrSig allows us to abstract over code
    which is indifferent to which.  However, there are some important
    differences, mostly owing to the fact that hsigs are proper
    modules (you `import Sig` directly) whereas HsBootFiles are
    temporary placeholders (you `import {-# SOURCE #-} Mod).
    When we finish compiling the true implementation of an hs-boot,
    we replace the HomeModInfo with the real HsSrcFile.  An HsigFile, on the
    other hand, is never replaced (in particular, we *cannot* use the
    HomeModInfo of the original HsSrcFile backing the signature, since it
    will export too many symbols.)

    Additionally, while HsSrcFile is the only Haskell file
    which has *code*, we do generate .o files for HsigFile, because
    this is how the recompilation checker figures out if a file
    needs to be recompiled.  These are fake object files which
    should NOT be linked against.
    -}

    data HsBootOrSig
      = HsBoot -- ^ .hs-boot file
      | Hsig   -- ^ .hsig file
       deriving (HsBootOrSig -> HsBootOrSig -> Bool
    (HsBootOrSig -> HsBootOrSig -> Bool)
    -> (HsBootOrSig -> HsBootOrSig -> Bool) -> Eq HsBootOrSig
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: HsBootOrSig -> HsBootOrSig -> Bool
    == :: HsBootOrSig -> HsBootOrSig -> Bool
    $c/= :: HsBootOrSig -> HsBootOrSig -> Bool
    /= :: HsBootOrSig -> HsBootOrSig -> Bool
    Eq, Eq HsBootOrSig
    Eq HsBootOrSig =>
    (HsBootOrSig -> HsBootOrSig -> Ordering)
    -> (HsBootOrSig -> HsBootOrSig -> Bool)
    -> (HsBootOrSig -> HsBootOrSig -> Bool)
    -> (HsBootOrSig -> HsBootOrSig -> Bool)
    -> (HsBootOrSig -> HsBootOrSig -> Bool)
    -> (HsBootOrSig -> HsBootOrSig -> HsBootOrSig)
    -> (HsBootOrSig -> HsBootOrSig -> HsBootOrSig)
    -> Ord HsBootOrSig
    HsBootOrSig -> HsBootOrSig -> Bool
    HsBootOrSig -> HsBootOrSig -> Ordering
    HsBootOrSig -> HsBootOrSig -> HsBootOrSig
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: HsBootOrSig -> HsBootOrSig -> Ordering
    compare :: HsBootOrSig -> HsBootOrSig -> Ordering
    $c< :: HsBootOrSig -> HsBootOrSig -> Bool
    < :: HsBootOrSig -> HsBootOrSig -> Bool
    $c<= :: HsBootOrSig -> HsBootOrSig -> Bool
    <= :: HsBootOrSig -> HsBootOrSig -> Bool
    $c> :: HsBootOrSig -> HsBootOrSig -> Bool
    > :: HsBootOrSig -> HsBootOrSig -> Bool
    $c>= :: HsBootOrSig -> HsBootOrSig -> Bool
    >= :: HsBootOrSig -> HsBootOrSig -> Bool
    $cmax :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
    max :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
    $cmin :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
    min :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
    Ord, Int -> HsBootOrSig -> ShowS
    [HsBootOrSig] -> ShowS
    HsBootOrSig -> String
    (Int -> HsBootOrSig -> ShowS)
    -> (HsBootOrSig -> String)
    -> ([HsBootOrSig] -> ShowS)
    -> Show HsBootOrSig
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> HsBootOrSig -> ShowS
    showsPrec :: Int -> HsBootOrSig -> ShowS
    $cshow :: HsBootOrSig -> String
    show :: HsBootOrSig -> String
    $cshowList :: [HsBootOrSig] -> ShowS
    showList :: [HsBootOrSig] -> ShowS
    Show)

    data HscSource
       -- | .hs file
       = HsSrcFile
       -- | .hs-boot or .hsig file
       | HsBootOrSig !HsBootOrSig
       deriving (HscSource -> HscSource -> Bool
    (HscSource -> HscSource -> Bool)
    -> (HscSource -> HscSource -> Bool) -> Eq HscSource
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: HscSource -> HscSource -> Bool
    == :: HscSource -> HscSource -> Bool
    $c/= :: HscSource -> HscSource -> Bool
    /= :: HscSource -> HscSource -> Bool
    Eq, Eq HscSource
    Eq HscSource =>
    (HscSource -> HscSource -> Ordering)
    -> (HscSource -> HscSource -> Bool)
    -> (HscSource -> HscSource -> Bool)
    -> (HscSource -> HscSource -> Bool)
    -> (HscSource -> HscSource -> Bool)
    -> (HscSource -> HscSource -> HscSource)
    -> (HscSource -> HscSource -> HscSource)
    -> Ord HscSource
    HscSource -> HscSource -> Bool
    HscSource -> HscSource -> Ordering
    HscSource -> HscSource -> HscSource
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: HscSource -> HscSource -> Ordering
    compare :: HscSource -> HscSource -> Ordering
    $c< :: HscSource -> HscSource -> Bool
    < :: HscSource -> HscSource -> Bool
    $c<= :: HscSource -> HscSource -> Bool
    <= :: HscSource -> HscSource -> Bool
    $c> :: HscSource -> HscSource -> Bool
    > :: HscSource -> HscSource -> Bool
    $c>= :: HscSource -> HscSource -> Bool
    >= :: HscSource -> HscSource -> Bool
    $cmax :: HscSource -> HscSource -> HscSource
    max :: HscSource -> HscSource -> HscSource
    $cmin :: HscSource -> HscSource -> HscSource
    min :: HscSource -> HscSource -> HscSource
    Ord, Int -> HscSource -> ShowS
    [HscSource] -> ShowS
    HscSource -> String
    (Int -> HscSource -> ShowS)
    -> (HscSource -> String)
    -> ([HscSource] -> ShowS)
    -> Show HscSource
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> HscSource -> ShowS
    showsPrec :: Int -> HscSource -> ShowS
    $cshow :: HscSource -> String
    show :: HscSource -> String
    $cshowList :: [HscSource] -> ShowS
    showList :: [HscSource] -> ShowS
    Show)

    {-# COMPLETE HsSrcFile, HsBootFile, HsigFile #-}
    pattern HsBootFile, HsigFile :: HscSource
    pattern $mHsBootFile :: forall {r}. HscSource -> ((# #) -> r) -> ((# #) -> r) -> r
    $bHsBootFile :: HscSource
    HsBootFile = HsBootOrSig HsBoot
    pattern $mHsigFile :: forall {r}. HscSource -> ((# #) -> r) -> ((# #) -> r) -> r
    $bHsigFile :: HscSource
    HsigFile   = HsBootOrSig Hsig

    -- | Tests if an 'HscSource' is a boot file, primarily for constructing elements
    -- of 'BuildModule'. We conflate signatures and modules because they are bound
    -- in the same namespace; only boot interfaces can be disambiguated with
    -- `import {-# SOURCE #-}`.
    hscSourceToIsBoot :: HscSource -> IsBootInterface
    hscSourceToIsBoot :: HscSource -> IsBootInterface
    hscSourceToIsBoot HscSource
    HsBootFile = IsBootInterface
    IsBoot
    hscSourceToIsBoot HscSource
    _ = IsBootInterface
    NotBoot

    instance Binary HscSource where
        put_ :: WriteBinHandle -> HscSource -> IO ()
    put_ WriteBinHandle
    bh HscSource
    HsSrcFile = WriteBinHandle -> Word8 -> IO ()
    putByte WriteBinHandle
    bh Word8
    0
        put_ WriteBinHandle
    bh HscSource
    HsBootFile = WriteBinHandle -> Word8 -> IO ()
    putByte WriteBinHandle
    bh Word8
    1
        put_ WriteBinHandle
    bh HscSource
    HsigFile = WriteBinHandle -> Word8 -> IO ()
    putByte WriteBinHandle
    bh Word8
    2
        get :: ReadBinHandle -> IO HscSource
    get ReadBinHandle
    bh = do
            h <- ReadBinHandle -> IO Word8
    getByte ReadBinHandle
    bh
            case h of
                Word8
    0 -> HscSource -> IO HscSource
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return HscSource
    HsSrcFile
                Word8
    1 -> HscSource -> IO HscSource
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return HscSource
    HsBootFile
                Word8
    _ -> HscSource -> IO HscSource
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return HscSource
    HsigFile

    hscSourceString :: HscSource -> String
    hscSourceString :: HscSource -> String
    hscSourceString HscSource
    HsSrcFile  = String
    ""
    hscSourceString HscSource
    HsBootFile = String
    "[boot]"
    hscSourceString HscSource
    HsigFile   = String
    "[sig]"

    -- See Note [HscSource types]
    isHsBootOrSig :: HscSource -> Bool
    isHsBootOrSig :: HscSource -> Bool
    isHsBootOrSig (HsBootOrSig HsBootOrSig
    _) = Bool
    True
    isHsBootOrSig HscSource
    HsSrcFile       = Bool
    False

    isHsBootFile :: HscSource -> Bool
    isHsBootFile :: HscSource -> Bool
    isHsBootFile HscSource
    HsBootFile = Bool
    True
    isHsBootFile HscSource
    _          = Bool
    False

    isHsigFile :: HscSource -> Bool
    isHsigFile :: HscSource -> Bool
    isHsigFile HscSource
    HsigFile = Bool
    True
    isHsigFile HscSource
    _        = Bool
    False