packages feed

liquidhaskell-0.8.10.7: src/Language/Haskell/Liquid/GHC/API/StableModule.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
module Language.Haskell.Liquid.GHC.API.StableModule (
    StableModule
  -- * Constructing a 'StableModule'
  , mkStableModule
  -- * Converting a 'StableModule' into a standard 'Module'
  , unStableModule
  -- * Utility functions
  , toStableModule
  , renderModule
  ) where

import qualified GHC

#ifdef MIN_VERSION_GLASGOW_HASKELL
#if !MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
import qualified Module as GHC
#else
import qualified GHC.Unit.Types as GHC
import qualified GHC.Unit.Module as GHC
#endif
#endif

import           Data.Hashable
import           GHC.Generics            hiding (to, moduleName)
import           Data.Binary

-- | A newtype wrapper around a 'Module' which:
--
-- * Allows a 'Module' to be serialised (i.e. it has a 'Binary' instance)
-- * It tries to use stable comparison and equality under the hood.
--
newtype StableModule =
  StableModule { unStableModule :: GHC.Module }
  deriving Generic

-- | Converts a 'Module' into a 'StableModule'.
toStableModule :: GHC.Module -> StableModule
toStableModule = StableModule

moduleUnitId :: GHC.Module -> GHC.UnitId
#ifdef MIN_VERSION_GLASGOW_HASKELL
#if !MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
moduleUnitId = GHC.moduleUnitId
#else
moduleUnitId = GHC.toUnitId . GHC.moduleUnit
#endif
#endif

renderModule :: GHC.Module -> String
renderModule m =    "Module { unitId = " <> (GHC.unitIdString . moduleUnitId $ m)
                 <> ", name = " <> show (GHC.moduleName m)
                 <> " }"

-- These two orphans originally lived inside module 'Language.Haskell.Liquid.Types.Types'.
instance Hashable GHC.ModuleName where
  hashWithSalt i = hashWithSalt i . show

instance Show GHC.ModuleName where
  show = GHC.moduleNameString

instance Hashable StableModule where
  hashWithSalt s (StableModule mdl) = hashWithSalt s (GHC.moduleStableString mdl)

instance Ord StableModule where
  (StableModule m1) `compare` (StableModule m2) = GHC.stableModuleCmp m1 m2

instance Eq StableModule where
  (StableModule m1) == (StableModule m2) = (m1 `GHC.stableModuleCmp` m2) == EQ

instance Show StableModule where
    show (StableModule mdl) = "Stable" ++ renderModule mdl

instance Binary StableModule where

    put (StableModule mdl) = do
      put (GHC.unitIdString . moduleUnitId $ mdl)
      put (GHC.moduleNameString . GHC.moduleName $ mdl)

    get = do
      uidStr <- get
      mnStr  <- get
      pure $ mkStableModule (GHC.stringToUnitId uidStr) (GHC.mkModuleName mnStr)

--
-- Compat shim layer
--

-- | Creates a new 'StableModule' out of a 'ModuleName' and a 'UnitId'.
mkStableModule :: GHC.UnitId -> GHC.ModuleName -> StableModule
#ifdef MIN_VERSION_GLASGOW_HASKELL
#if !MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
mkStableModule uid modName = StableModule (GHC.mkModule uid modName)
#else
mkStableModule uid modName =
  let realUnit = GHC.RealUnit $ GHC.Definite uid
  in StableModule (GHC.Module realUnit modName)
#endif
#endif