{-# LANGUAGE CPP #-} module Polysemy.Plugin.Fundep.Stuff ( PolysemyStuff (..) , LookupState (..) , polysemyStuff ) where import Data.Kind (Type) import GHC (Name, Class, TyCon, mkModuleName) import GHC.TcPluginM.Extra (lookupModule, lookupName) #if __GLASGOW_HASKELL__ >= 900 import GHC.Data.FastString (fsLit) import GHC.Types.Name.Occurrence (mkTcOcc) import GHC.Tc.Plugin (TcPluginM, tcLookupClass, tcLookupTyCon, unsafeTcPluginTcM) import GHC.Plugins (getDynFlags) import GHC.Unit.State (lookupModuleWithSuggestions, LookupResult (..), UnitState) import GHC.Utils.Outputable (text, (<+>), ($$)) #if __GLASGOW_HASKELL__ >= 902 import GHC.Tc.Plugin (getTopEnv) import GHC.Utils.Panic (pprPanic) import GHC.Driver.Env (hsc_units) #if __GLASGOW_HASKELL__ >= 904 import GHC.Types.PkgQual (PkgQual(NoPkgQual)) #endif #else import GHC.Plugins (unitState) import GHC.Utils.Outputable(pprPanic) #endif #else import FastString (fsLit) import OccName (mkTcOcc) import TcPluginM (TcPluginM, tcLookupClass, tcLookupTyCon, unsafeTcPluginTcM) import GhcPlugins (getDynFlags) import Packages (lookupModuleWithSuggestions, LookupResult (..)) import Outputable (pprPanic, text, (<+>), ($$)) #endif ------------------------------------------------------------------------------ -- | All of the things from "polysemy" that we need access to in the plugin. -- When @l ~ 'Locations@, each of these is just a pair of strings. When @l -- ~ 'Things@, it's actually references to the stuff. data PolysemyStuff (l :: LookupState) = PolysemyStuff { findClass :: ThingOf l Class , semTyCon :: ThingOf l TyCon } ------------------------------------------------------------------------------ -- | All of the things we need to lookup. polysemyStuffLocations :: PolysemyStuff 'Locations polysemyStuffLocations = PolysemyStuff { findClass = ("Polysemy.Internal.Union", "Member") , semTyCon = ("Polysemy.Internal", "Sem") } #if __GLASGOW_HASKELL__ >= 900 ------------------------------------------------------------------------------ -- | GHC-version-dependent access of the UnitState getUnitState :: TcPluginM UnitState getUnitState = do #if __GLASGOW_HASKELL__ >= 902 topState <- getTopEnv return (hsc_units topState) #else dflags <- unsafeTcPluginTcM getDynFlags return (unitState dflags) #endif #endif ------------------------------------------------------------------------------ -- | Lookup all of the 'PolysemyStuff'. polysemyStuff :: TcPluginM (PolysemyStuff 'Things) polysemyStuff = do #if __GLASGOW_HASKELL__ >= 900 theUnitState <- getUnitState #else dflags <- unsafeTcPluginTcM getDynFlags #endif let error_msg = pprPanic "polysemy-plugin" $ text "" $$ text "--------------------------------------------------------------------------------" $$ text "`polysemy-plugin` is loaded, but" <+> text "`polysemy` isn't available as a package." $$ text "Probable fix: add `polysemy` to your cabal `build-depends`" $$ text "--------------------------------------------------------------------------------" $$ text "" case lookupModuleWithSuggestions #if __GLASGOW_HASKELL__ >= 900 theUnitState #else dflags #endif (mkModuleName "Polysemy") #if __GLASGOW_HASKELL__ >= 904 NoPkgQual #else Nothing #endif of LookupHidden _ _ -> error_msg LookupNotFound _ -> error_msg #if __GLASGOW_HASKELL__ >= 806 LookupUnusable _ -> error_msg #endif _ -> pure () let PolysemyStuff a b = polysemyStuffLocations PolysemyStuff <$> doLookup a <*> doLookup b ------------------------------------------------------------------------------ -- | Data kind for 'ThingOf'. data LookupState = Locations | Things ------------------------------------------------------------------------------ -- | HKD indexed by the 'LookupState'; used by 'PolysemyStuff'. type family ThingOf (l :: LookupState) (a :: Type) :: Type where ThingOf 'Locations _ = (String, String) ThingOf 'Things a = a ------------------------------------------------------------------------------ -- | Things that can be found in a 'TcPluginM' environment. class CanLookup a where lookupStrategy :: Name -> TcPluginM a instance CanLookup Class where lookupStrategy = tcLookupClass instance CanLookup TyCon where lookupStrategy = tcLookupTyCon ------------------------------------------------------------------------------ -- | Transform a @'ThingOf' 'Locations@ into a @'ThingOf' 'Things@. doLookup :: CanLookup a => ThingOf 'Locations a -> TcPluginM (ThingOf 'Things a) doLookup (mdname, name) = do md <- lookupModule (mkModuleName mdname) $ fsLit "polysemy" nm <- lookupName md $ mkTcOcc name lookupStrategy nm