ghc-tcplugin-api 0.14.0.0 → 0.15.0.0
raw patch · 4 files changed
+313/−54 lines, 4 filesdep +template-haskelldep ~ghcPVP ok
version bump matches the API change (PVP)
Dependencies added: template-haskell
Dependency ranges changed: ghc
API changes (from Hackage documentation)
- GHC.TcPlugin.API: ctev_dest :: CtEvidence -> TcEvDest
- GHC.TcPlugin.API: ctev_evar :: CtEvidence -> EvVar
- GHC.TcPlugin.API: ctev_loc :: CtEvidence -> CtLoc
- GHC.TcPlugin.API: ctev_pred :: CtEvidence -> TcPredType
- GHC.TcPlugin.API: tcPluginIO :: MonadTcPlugin m => IO a -> m a
+ GHC.TcPlugin.API: [ch_hetero_kind] :: CoercionHole -> Bool
+ GHC.TcPlugin.API: charKind :: Type
+ GHC.TcPlugin.API: className :: Class -> Name
+ GHC.TcPlugin.API: ctEvId :: HasDebugCallStack => Ct -> EvVar
+ GHC.TcPlugin.API: ctEvLoc :: CtEvidence -> CtLoc
+ GHC.TcPlugin.API: ctEvPred :: CtEvidence -> TcPredType
+ GHC.TcPlugin.API: evDFunApp :: DFunId -> [Type] -> [EvExpr] -> EvExpr
+ GHC.TcPlugin.API: evId :: EvId -> EvExpr
+ GHC.TcPlugin.API: isEqClassPred :: PredType -> Bool
+ GHC.TcPlugin.API: isEqPred :: PredType -> Bool
+ GHC.TcPlugin.API: isGiven :: CtEvidence -> Bool
+ GHC.TcPlugin.API: isWanted :: CtEvidence -> Bool
+ GHC.TcPlugin.API: lookupTHName :: forall (s :: TcPluginStage). (Monad (TcPluginM s), MonadTcPlugin (TcPluginM s)) => Name -> TcPluginM s Name
+ GHC.TcPlugin.API: natKind :: Type
+ GHC.TcPlugin.API: nonDetCmpType :: Type -> Type -> Ordering
+ GHC.TcPlugin.API: symbolKind :: Type
+ GHC.TcPlugin.API: tyConName :: TyCon -> Name
+ GHC.TcPlugin.API: typeKind :: HasDebugCallStack => Type -> Kind
+ GHC.TcPlugin.API.Internal: instance (GHC.Base.Monad (GHC.TcPlugin.API.Internal.TcPluginM s), GHC.TcPlugin.API.Internal.MonadTcPlugin (GHC.TcPlugin.API.Internal.TcPluginM s)) => Control.Monad.IO.Class.MonadIO (GHC.TcPlugin.API.Internal.TcPluginM s)
- GHC.TcPlugin.API: CoercionHole :: CoVar -> IORef (Maybe Coercion) -> CoercionHole
+ GHC.TcPlugin.API: CoercionHole :: CoVar -> IORef (Maybe Coercion) -> Bool -> CoercionHole
- GHC.TcPlugin.API: NotFound :: [FilePath] -> Maybe Unit -> [Unit] -> [Unit] -> [(Unit, UnusableUnitReason)] -> [ModuleSuggestion] -> FindResult
+ GHC.TcPlugin.API: NotFound :: [FilePath] -> Maybe Unit -> [Unit] -> [Unit] -> [UnusableUnit] -> [ModuleSuggestion] -> FindResult
- GHC.TcPlugin.API: TcPlugin :: TcPluginM Init s -> (s -> TcPluginSolver) -> (s -> UniqFM TyCon TcPluginRewriter) -> (s -> TcPluginM Stop ()) -> TcPlugin
+ GHC.TcPlugin.API: TcPlugin :: TcPluginM 'Init s -> (s -> TcPluginSolver) -> (s -> UniqFM TyCon TcPluginRewriter) -> (s -> TcPluginM 'Stop ()) -> TcPlugin
- GHC.TcPlugin.API: [fr_unusables] :: FindResult -> [(Unit, UnusableUnitReason)]
+ GHC.TcPlugin.API: [fr_unusables] :: FindResult -> [UnusableUnit]
- GHC.TcPlugin.API: [tcPluginInit] :: TcPlugin -> TcPluginM Init s
+ GHC.TcPlugin.API: [tcPluginInit] :: TcPlugin -> TcPluginM 'Init s
- GHC.TcPlugin.API: [tcPluginStop] :: TcPlugin -> s -> TcPluginM Stop ()
+ GHC.TcPlugin.API: [tcPluginStop] :: TcPlugin -> s -> TcPluginM 'Stop ()
- GHC.TcPlugin.API: askDeriveds :: TcPluginM Solve [Ct]
+ GHC.TcPlugin.API: askDeriveds :: TcPluginM 'Solve [Ct]
- GHC.TcPlugin.API: askEvBinds :: TcPluginM Solve EvBindsVar
+ GHC.TcPlugin.API: askEvBinds :: TcPluginM 'Solve EvBindsVar
- GHC.TcPlugin.API: askRewriteEnv :: TcPluginM Rewrite RewriteEnv
+ GHC.TcPlugin.API: askRewriteEnv :: TcPluginM 'Rewrite RewriteEnv
- GHC.TcPlugin.API: class (Monad m, (forall x y. Coercible x y => Coercible (m x) (m y))) => MonadTcPlugin (m :: Type -> Type)
+ GHC.TcPlugin.API: class (Monad m, forall x y. Coercible x y => Coercible m x m y) => MonadTcPlugin (m :: Type -> Type)
- GHC.TcPlugin.API: class MonadTcPlugin m => MonadTcPluginWork m
+ GHC.TcPlugin.API: class MonadTcPlugin m => MonadTcPluginWork (m :: Type -> Type)
- GHC.TcPlugin.API: class () => Outputable a
+ GHC.TcPlugin.API: class Outputable a
- GHC.TcPlugin.API: data () => Boxity
+ GHC.TcPlugin.API: data Boxity
- GHC.TcPlugin.API: data () => Class
+ GHC.TcPlugin.API: data Class
- GHC.TcPlugin.API: data () => Coercion
+ GHC.TcPlugin.API: data Coercion
- GHC.TcPlugin.API: data () => CoercionHole
+ GHC.TcPlugin.API: data CoercionHole
- GHC.TcPlugin.API: data () => Ct
+ GHC.TcPlugin.API: data Ct
- GHC.TcPlugin.API: data () => CtEvidence
+ GHC.TcPlugin.API: data CtEvidence
- GHC.TcPlugin.API: data () => CtFlavour
+ GHC.TcPlugin.API: data CtFlavour
- GHC.TcPlugin.API: data () => CtLoc
+ GHC.TcPlugin.API: data CtLoc
- GHC.TcPlugin.API: data () => CtOrigin
+ GHC.TcPlugin.API: data CtOrigin
- GHC.TcPlugin.API: data () => DataCon
+ GHC.TcPlugin.API: data DataCon
- GHC.TcPlugin.API: data () => EqRel
+ GHC.TcPlugin.API: data EqRel
- GHC.TcPlugin.API: data () => EvBind
+ GHC.TcPlugin.API: data EvBind
- GHC.TcPlugin.API: data () => EvBindsVar
+ GHC.TcPlugin.API: data EvBindsVar
- GHC.TcPlugin.API: data () => EvTerm
+ GHC.TcPlugin.API: data EvTerm
- GHC.TcPlugin.API: data () => Expr b
+ GHC.TcPlugin.API: data Expr b
- GHC.TcPlugin.API: data () => FamInstEnv
+ GHC.TcPlugin.API: data FamInstEnv
- GHC.TcPlugin.API: data () => FastString
+ GHC.TcPlugin.API: data FastString
- GHC.TcPlugin.API: data () => FindResult
+ GHC.TcPlugin.API: data FindResult
- GHC.TcPlugin.API: data () => GenLocated l e
+ GHC.TcPlugin.API: data GenLocated l e
- GHC.TcPlugin.API: data () => InertSet
+ GHC.TcPlugin.API: data InertSet
- GHC.TcPlugin.API: data () => InstEnvs
+ GHC.TcPlugin.API: data InstEnvs
- GHC.TcPlugin.API: data () => MetaDetails
+ GHC.TcPlugin.API: data MetaDetails
- GHC.TcPlugin.API: data () => MetaInfo
+ GHC.TcPlugin.API: data MetaInfo
- GHC.TcPlugin.API: data () => ModuleName
+ GHC.TcPlugin.API: data ModuleName
- GHC.TcPlugin.API: data () => Name
+ GHC.TcPlugin.API: data Name
- GHC.TcPlugin.API: data () => OccName
+ GHC.TcPlugin.API: data OccName
- GHC.TcPlugin.API: data () => PkgQual
+ GHC.TcPlugin.API: data PkgQual
- GHC.TcPlugin.API: data () => Pred
+ GHC.TcPlugin.API: data Pred
- GHC.TcPlugin.API: data () => PromotionFlag
+ GHC.TcPlugin.API: data PromotionFlag
- GHC.TcPlugin.API: data () => QCInst
+ GHC.TcPlugin.API: data QCInst
- GHC.TcPlugin.API: data () => Reduction
+ GHC.TcPlugin.API: data Reduction
- GHC.TcPlugin.API: data () => RewriteEnv
+ GHC.TcPlugin.API: data RewriteEnv
- GHC.TcPlugin.API: data () => Role
+ GHC.TcPlugin.API: data Role
- GHC.TcPlugin.API: data () => SDoc
+ GHC.TcPlugin.API: data SDoc
- GHC.TcPlugin.API: data () => TcEvDest
+ GHC.TcPlugin.API: data TcEvDest
- GHC.TcPlugin.API: data () => TcGblEnv
+ GHC.TcPlugin.API: data TcGblEnv
- GHC.TcPlugin.API: data () => TcLclEnv
+ GHC.TcPlugin.API: data TcLclEnv
- GHC.TcPlugin.API: data () => TcLevel
+ GHC.TcPlugin.API: data TcLevel
- GHC.TcPlugin.API: data () => TcPluginRewriteResult
+ GHC.TcPlugin.API: data TcPluginRewriteResult
- GHC.TcPlugin.API: data () => TcPluginSolveResult
+ GHC.TcPlugin.API: data TcPluginSolveResult
- GHC.TcPlugin.API: data () => TcS a
+ GHC.TcPlugin.API: data TcS a
- GHC.TcPlugin.API: data () => TcTyThing
+ GHC.TcPlugin.API: data TcTyThing
- GHC.TcPlugin.API: data () => TupleSort
+ GHC.TcPlugin.API: data TupleSort
- GHC.TcPlugin.API: data () => TyCon
+ GHC.TcPlugin.API: data TyCon
- GHC.TcPlugin.API: data () => TyThing
+ GHC.TcPlugin.API: data TyThing
- GHC.TcPlugin.API: data () => Type
+ GHC.TcPlugin.API: data Type
- GHC.TcPlugin.API: data () => UniqDFM key ele
+ GHC.TcPlugin.API: data UniqDFM key ele
- GHC.TcPlugin.API: data () => UniqFM key ele
+ GHC.TcPlugin.API: data UniqFM key ele
- GHC.TcPlugin.API: data () => Unique
+ GHC.TcPlugin.API: data Unique
- GHC.TcPlugin.API: data () => UnitId
+ GHC.TcPlugin.API: data UnitId
- GHC.TcPlugin.API: data () => UnivCoProvenance
+ GHC.TcPlugin.API: data UnivCoProvenance
- GHC.TcPlugin.API: evCast :: EvExpr -> TcCoercion -> EvTerm
+ GHC.TcPlugin.API: evCast :: EvExpr -> Coercion -> EvExpr
- GHC.TcPlugin.API: evDataConApp :: DataCon -> [Type] -> [EvExpr] -> EvTerm
+ GHC.TcPlugin.API: evDataConApp :: DataCon -> [Type] -> [EvExpr] -> EvExpr
- GHC.TcPlugin.API: newCoercionHole :: PredType -> TcPluginM Solve CoercionHole
+ GHC.TcPlugin.API: newCoercionHole :: PredType -> TcPluginM 'Solve CoercionHole
- GHC.TcPlugin.API: newEvVar :: PredType -> TcPluginM Solve EvVar
+ GHC.TcPlugin.API: newEvVar :: PredType -> TcPluginM 'Solve EvVar
- GHC.TcPlugin.API: newGiven :: CtLoc -> PredType -> EvExpr -> TcPluginM Solve CtEvidence
+ GHC.TcPlugin.API: newGiven :: CtLoc -> PredType -> EvTerm -> TcPluginM 'Solve CtEvidence
- GHC.TcPlugin.API: readTcRef :: TcRef a -> TcRnIf gbl lcl a
+ GHC.TcPlugin.API: readTcRef :: MonadIO m => TcRef a -> m a
- GHC.TcPlugin.API: setCtLocRewriteM :: TcPluginM Rewrite a -> TcPluginM Rewrite a
+ GHC.TcPlugin.API: setCtLocRewriteM :: TcPluginM 'Rewrite a -> TcPluginM 'Rewrite a
- GHC.TcPlugin.API: setEvBind :: EvBind -> TcPluginM Solve ()
+ GHC.TcPlugin.API: setEvBind :: EvBind -> TcPluginM 'Solve ()
- GHC.TcPlugin.API: type TcPluginRewriter = -- | Givens [Ct] -> -- | Type family arguments (saturated) [Type] -> TcPluginM Rewrite TcPluginRewriteResult
+ GHC.TcPlugin.API: type TcPluginRewriter = [Ct] -> [Type] -> TcPluginM 'Rewrite TcPluginRewriteResult
- GHC.TcPlugin.API: type TcPluginSolver = -- | Givens [Ct] -> -- | Wanteds [Ct] -> TcPluginM Solve TcPluginSolveResult
+ GHC.TcPlugin.API: type TcPluginSolver = [Ct] -> [Ct] -> TcPluginM 'Solve TcPluginSolveResult
- GHC.TcPlugin.API: writeMetaTyVar :: HasDebugCallStack => TcTyVar -> TcType -> TcM ()
+ GHC.TcPlugin.API: writeMetaTyVar :: HasDebugCallStack => TcTyVar -> TcType -> ZonkM ()
- GHC.TcPlugin.API: writeTcRef :: TcRef a -> a -> TcRnIf gbl lcl ()
+ GHC.TcPlugin.API: writeTcRef :: MonadIO m => TcRef a -> a -> m ()
- GHC.TcPlugin.API.Internal: TcPlugin :: TcPluginM Init s -> (s -> TcPluginSolver) -> (s -> UniqFM TyCon TcPluginRewriter) -> (s -> TcPluginM Stop ()) -> TcPlugin
+ GHC.TcPlugin.API.Internal: TcPlugin :: TcPluginM 'Init s -> (s -> TcPluginSolver) -> (s -> UniqFM TyCon TcPluginRewriter) -> (s -> TcPluginM 'Stop ()) -> TcPlugin
- GHC.TcPlugin.API.Internal: [tcPluginInit] :: TcPlugin -> TcPluginM Init s
+ GHC.TcPlugin.API.Internal: [tcPluginInit] :: TcPlugin -> TcPluginM 'Init s
- GHC.TcPlugin.API.Internal: [tcPluginStop] :: TcPlugin -> s -> TcPluginM Stop ()
+ GHC.TcPlugin.API.Internal: [tcPluginStop] :: TcPlugin -> s -> TcPluginM 'Stop ()
- GHC.TcPlugin.API.Internal: askDeriveds :: TcPluginM Solve [Ct]
+ GHC.TcPlugin.API.Internal: askDeriveds :: TcPluginM 'Solve [Ct]
- GHC.TcPlugin.API.Internal: askEvBinds :: TcPluginM Solve EvBindsVar
+ GHC.TcPlugin.API.Internal: askEvBinds :: TcPluginM 'Solve EvBindsVar
- GHC.TcPlugin.API.Internal: askRewriteEnv :: TcPluginM Rewrite RewriteEnv
+ GHC.TcPlugin.API.Internal: askRewriteEnv :: TcPluginM 'Rewrite RewriteEnv
- GHC.TcPlugin.API.Internal: class (Monad m, (forall x y. Coercible x y => Coercible (m x) (m y))) => MonadTcPlugin (m :: Type -> Type)
+ GHC.TcPlugin.API.Internal: class (Monad m, forall x y. Coercible x y => Coercible m x m y) => MonadTcPlugin (m :: Type -> Type)
- GHC.TcPlugin.API.Internal: class MonadTcPlugin m => MonadTcPluginWork m
+ GHC.TcPlugin.API.Internal: class MonadTcPlugin m => MonadTcPluginWork (m :: Type -> Type)
- GHC.TcPlugin.API.Internal: type TcPluginRewriter = -- | Givens [Ct] -> -- | Type family arguments (saturated) [Type] -> TcPluginM Rewrite TcPluginRewriteResult
+ GHC.TcPlugin.API.Internal: type TcPluginRewriter = [Ct] -> [Type] -> TcPluginM 'Rewrite TcPluginRewriteResult
- GHC.TcPlugin.API.Internal: type TcPluginSolver = -- | Givens [Ct] -> -- | Wanteds [Ct] -> TcPluginM Solve TcPluginSolveResult
+ GHC.TcPlugin.API.Internal: type TcPluginSolver = [Ct] -> [Ct] -> TcPluginM 'Solve TcPluginSolveResult
- GHC.TcPlugin.API.Internal: unsafeWithRunInTcM :: MonadTcPlugin m => ((forall a. m a -> TcM a) -> TcM b) -> m b
+ GHC.TcPlugin.API.Internal: unsafeWithRunInTcM :: MonadTcPlugin m => ((forall a. () => m a -> TcM a) -> TcM b) -> m b
- GHC.TcPlugin.API.Names: Qualified :: String -> ModuleName -> PkgQual -> QualifiedName (thing :: Type)
+ GHC.TcPlugin.API.Names: Qualified :: String -> ModuleName -> PkgQual -> QualifiedName thing
- GHC.TcPlugin.API.Names: [module'] :: QualifiedName (thing :: Type) -> ModuleName
+ GHC.TcPlugin.API.Names: [module'] :: QualifiedName thing -> ModuleName
- GHC.TcPlugin.API.Names: [name] :: QualifiedName (thing :: Type) -> String
+ GHC.TcPlugin.API.Names: [name] :: QualifiedName thing -> String
- GHC.TcPlugin.API.Names: [package] :: QualifiedName (thing :: Type) -> PkgQual
+ GHC.TcPlugin.API.Names: [package] :: QualifiedName thing -> PkgQual
- GHC.TcPlugin.API.Names: data Promoted (thing :: k) :: Type
+ GHC.TcPlugin.API.Names: data Promoted (thing :: k)
- GHC.TcPlugin.API.Names: data QualifiedName (thing :: Type)
+ GHC.TcPlugin.API.Names: data QualifiedName thing
- GHC.TcPlugin.API.Names: lookup :: (Lookupable a, MonadTcPlugin m) => Name -> m (Wear Resolved a)
+ GHC.TcPlugin.API.Names: lookup :: (Lookupable a, MonadTcPlugin m) => Name -> m (Wear 'Resolved a)
- GHC.TcPlugin.API.Names: newtype () => Generically1 (f :: k -> Type) (a :: k)
+ GHC.TcPlugin.API.Names: newtype Generically1 (f :: k -> Type) (a :: k)
- GHC.TcPlugin.API.Names: resolveNames :: (MonadTcPlugin m, ResolveNames f) => f Named -> m (f Resolved)
+ GHC.TcPlugin.API.Names: resolveNames :: (MonadTcPlugin m, ResolveNames f) => f 'Named -> m (f 'Resolved)
- GHC.TcPlugin.API.Names: type family Wear (n :: NameResolution) (thing :: k) :: Type
+ GHC.TcPlugin.API.Names: type family Wear (n :: NameResolution) (thing :: k)
Files
- changelog.md +35/−0
- ghc-tcplugin-api.cabal +15/−3
- src/GHC/TcPlugin/API.hs +257/−51
- src/GHC/TcPlugin/API/Internal.hs +6/−0
changelog.md view
@@ -1,3 +1,38 @@+# Version 0.15.0.0 (2025-06-03) + +- Remove `tcPluginIO` in favour of new `MonadIO` instance. + To migrate, use `liftIO` instead of `tcPluginIO`. + +- Add `lookupTHName` function, which allows looking up Template Haskell names + in typechecker plugins. Useful in conjunction with `TemplateHaskellQuotes`. + +- Helper functions to construct evidence terms have been adjusted to return + values of type `EvExpr`, rather than `EvTerm`. This makes the functions more + composable, and allows typechecker plugin to provide evidence for quantified + constraints more easily. + + Affected functions: `evDFunApp`, `evDataConApp`, `evCast`. + + To migrate, you will need to manually wrap evidence terms with the + `EvExpr` constructor in places that expect an `EvTerm`. + +- Added `natKind`, `symbolKind` and `charKind` for the kinds of type-level + `Nat`, `Symbol` and `Char`. + +- Added several re-exports from the `ghc` library: + - `isGiven` & `isWanted`. + - `ctEvPred`, `ctEvId`, `ctEvExpr` and `ctEvLoc`. + - `className` & `tyConName`. + - `isEqPred` (unboxed equality) and `isEqClassPred` (boxed equality). + - `evId` & `ctEvId`. + - `typeKind`. + - `nonDetCmpType`. + +- Removed re-exports of `ctev_pred`, `ctev_loc`, `ctev_evar`, and `ctev_dest`. + + Migration: use `ctEvPred` instead of `ctev_pred` and `ctEvLoc` instead of `ctev_loc`. + Uses of `ctev_evar` and `ctev_dest` should be covered by `ctEvEvId` and/or + `ctEvExpr`. # Version 0.14.0.0 (2024-11-28)
ghc-tcplugin-api.cabal view
@@ -1,12 +1,12 @@ cabal-version: 3.0 name: ghc-tcplugin-api -version: 0.14.0.0 +version: 0.15.0.0 synopsis: An API for type-checker plugins. license: BSD-3-Clause build-type: Simple author: Sam Derbyshire maintainer: Sam Derbyshire -copyright: 2021-2024 Sam Derbyshire +copyright: 2021-2025 Sam Derbyshire homepage: https://github.com/sheaf/ghc-tcplugin-api category: Type System, GHC, Plugin description: @@ -37,9 +37,11 @@ containers >= 0.6 && < 0.8, ghc - >= 8.8 && < 9.14, + >= 8.8 && < 9.16, transformers >= 0.5 && < 0.7, + template-haskell + >= 2.15 && < 2.25, default-language: Haskell2010 @@ -72,6 +74,11 @@ , GHC.Types.Unique.DSet , GHC.Utils.Outputable + if impl(ghc >= 9.13.0) + -- Don't warn on exports of the form "pattern ClassPred". + -- We can migrate to using "data" when that becomes necessary. + ghc-options: -Wno-pattern-namespace-specifier + if impl(ghc >= 9.3.0) cpp-options: -DHAS_REWRITING else @@ -110,6 +117,8 @@ , DynFlags as GHC.Driver.Session , HscTypes as GHC.Driver.Types + , IfaceEnv as GHC.Iface.Env + , GhcPlugins as GHC.Plugins , TcPluginM as GHC.Tc.Plugin @@ -125,6 +134,7 @@ , Literal as GHC.Types.Literal , Name as GHC.Types.Name , OccName as GHC.Types.Name.Occurrence + , RdrName as GHC.Types.Name.Reader , SrcLoc as GHC.Types.SrcLoc , Unique as GHC.Types.Unique , UniqDFM as GHC.Types.Unique.DFM @@ -152,6 +162,7 @@ ( Predicate as GHC.Core.Predicate , Constraint as GHC.Tc.Types.Constraint , TcOrigin as GHC.Tc.Types.Origin + , GHC.ThToHs as GHC.ThToHs ) else @@ -161,4 +172,5 @@ ( Type as GHC.Core.Predicate , TcRnTypes as GHC.Tc.Types.Constraint , TcRnTypes as GHC.Tc.Types.Origin + , Convert as GHC.ThToHs )
src/GHC/TcPlugin/API.hs view
@@ -1,6 +1,9 @@ {-# LANGUAGE CPP #-} + +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} @@ -64,7 +67,6 @@ -- typeclass providing overloading (for operations that work in all stages). , TcPluginStage(..), MonadTcPlugin , TcPluginM - , tcPluginIO -- *** Emitting new work, and throwing type-errors @@ -80,10 +82,23 @@ -- | Name resolution is usually the first step in writing a type-checking plugin: -- plugins need to look up the names of the objects they want to manipulate. -- - -- For instance, to lookup the type family @MyFam@ in module @MyModule@ in package @my-pkg@: + -- The most convenient way to look up a Name is to bring the name into scope + -- in the module defining the plugin, and use @TemplateHaskellQuotes@ + -- in conjunction with the 'lookupTHName' function. -- - -- > lookupMyModule :: MonadTcPlugin m => m Module - -- > lookupMyModule = do + -- > import Data.Maybe + -- > + -- > lookupMaybeTyCon :: MonadTcPluginM m => m TyCon + -- > lookupMaybeTyCon = lookupTHName ''Maybe >>= tcLookupTyCon + -- + -- This is recommended over manually looking up the package and module + -- name, because the manual method does not robustly deal with re-exports; + -- one must specify the exact package/module which defines the identifier. + -- For instance, to manually lookup the type family @MyFam@ in module + -- @MyModule@ in package @my-pkg@: + -- + -- > lookupMyFam :: MonadTcPluginM m => m Name + -- > lookupMyFam = do -- > let modlName = mkModuleName "MyModule" -- > pkgName = Just $ fsLit "my-pkg" -- > pkgQual <- resolveImport modlName pkgName @@ -99,31 +114,38 @@ -- to the other stages: the plugin initialisation is called only once in each module -- that the plugin is used, whereas the solver and rewriter are usually called repeatedly. - -- ** Packages and modules + -- ** Name resolution: TH method + -- | Look up a Name from a Template Haskell Name (e.g. a Name constructed + -- using TemplateHaskellQuotes). + , lookupTHName + + -- ** Name resolution: manual method + -- *** Packages and modules + -- | Use these functions to lookup a module, -- from the current package or imported packages. , findImportedModule, resolveImport, fsLit, unpackFS, mkModuleName , unitIdFS, stringToUnitId, pkgQualToPkgName , Module, ModuleName, FindResult(..), UnitId, PkgQual - -- ** Names + -- *** Names - -- *** Occurence names + -- **** Occurence names -- | The most basic type of name is the 'OccName', which is a -- simple textual name within a namespace (e.g. the class namespace), -- without any disambiguation (no module qualifier, etc). , mkVarOcc, mkDataOcc, mkTyVarOcc, mkTcOcc, mkClsOcc - -- *** Names + -- **** Names -- | After having looked up the 'Module', we can obtain the full 'Name' -- referred to by an 'OccName'. This is fully unambiguous, as it -- contains a 'Unique' identifier for the name. , lookupOrig - -- *** 'TyCon', 'Class', 'DataCon', etc + -- ** Name resolution: resolving the Name to a 'TyCon', 'Class', 'DataCon', etc -- | Finally, we can obtain the actual objects we're interested in handling, -- such as classes, type families, data constructors... by looking them up @@ -244,8 +266,12 @@ , readTcRef, writeTcRef -- | == Some further functions for inspecting constraints - , eqType + , eqType, nonDetCmpType , ctLoc, ctEvidence, ctFlavour, ctEqRel, ctOrigin + , ctEvPred, ctEvId, ctEvExpr, ctEvLoc + , isGiven, isWanted + , isEqPred, isEqClassPred + , className, tyConName -- ** Constraint evidence @@ -282,13 +308,11 @@ -- by combining evidence that is already available. , mkPluginUnivEvTerm - , evDataConApp + , evDFunApp, evDataConApp , newEvVar, setEvBind - , evCoercion, evCast - , ctEvExpr + , evId, evCoercion, evCast , askEvBinds, lookupEvBind, eb_lhs, eb_rhs , newName, mkLocalId, mkTyVar - , ctev_pred, ctev_evar, ctev_loc, ctev_dest -- *** Class dictionaries @@ -395,6 +419,7 @@ -- ** Type literals (natural numbers, type-level strings) , mkNumLitTy, isNumLitTy , mkStrLitTy, isStrLitTy + , natKind, symbolKind, charKind -- ** Creating and decomposing applications , mkTyConTy, mkTyConApp, mkAppTy, mkAppTys @@ -408,6 +433,8 @@ , mkForAllTy, mkForAllTys , mkPiTy, mkPiTys + -- ** Kinds + , typeKind #if MIN_VERSION_ghc(9,0,0) , Mult @@ -503,6 +530,19 @@ -- ghc import GHC ( TyThing(..) ) +import GHC.Builtin.Names + ( hasKey + , eqPrimTyConKey, eqReprPrimTyConKey + , heqTyConKey, eqTyConKey, coercibleTyConKey + ) +import GHC.Builtin.Types + ( typeSymbolKind, charTy +#if MIN_VERSION_ghc(9,1,0) + , naturalTy +#else + , typeNatKind +#endif + ) #if !MIN_VERSION_ghc(9,0,0) import GHC.Builtin.Types ( intDataCon ) @@ -510,12 +550,12 @@ ( intPrimTy ) #endif import GHC.Core - ( CoreBndr, CoreExpr, Expr(..) ) + ( CoreBndr, CoreExpr, Expr(..), mkTyApps, mkApps ) import GHC.Core.Class ( Class(..), FunDep ) import GHC.Core.Coercion ( mkReflCo, mkSymCo, mkTransCo - , mkUnivCo + , mkUnivCo, isReflCo #if !MIN_VERSION_ghc(9,13,0) && MIN_VERSION_ghc(8,10,0) , mkPrimEqPredRole #endif @@ -524,7 +564,7 @@ ( Role(..) ) import GHC.Core.DataCon ( DataCon - , classDataCon, promoteDataCon + , classDataCon, promoteDataCon, dataConWrapId ) import GHC.Core.FamInstEnv ( FamInstEnv ) @@ -552,7 +592,7 @@ ( Reduction(..) ) #endif import GHC.Core.TyCon - ( TyCon(..) ) + ( TyCon(..), tyConClass_maybe ) #if MIN_VERSION_ghc(9,6,0) import GHC.Core.TyCo.Compare ( eqType ) @@ -589,6 +629,7 @@ , mkAppTy, mkAppTys, isTyVarTy, getTyVar_maybe , mkCoercionTy, isCoercionTy, isCoercionTy_maybe , mkNumLitTy, isNumLitTy, mkStrLitTy, isStrLitTy + , typeKind #if !MIN_VERSION_ghc(9,6,0) , eqType #endif @@ -600,6 +641,28 @@ ) import GHC.Data.FastString ( FastString, fsLit, unpackFS ) +#if MIN_VERSION_ghc(9,5,0) +import GHC.Plugins + ( thNameToGhcNameIO ) +#else +import Data.Maybe + ( listToMaybe ) +#if MIN_VERSION_ghc(9,3,0) +import GHC.Iface.Env + ( lookupNameCache ) +#else +import GHC.Iface.Env + ( lookupOrigIO ) +#endif +import GHC.ThToHs + ( thRdrNameGuesses ) +import GHC.Types.Name + ( isExternalName ) +import GHC.Types.Name.Reader + ( isExact_maybe, isOrig_maybe ) +import GHC.Utils.Monad + ( mapMaybeM ) +#endif import qualified GHC.Tc.Plugin as GHC #if MIN_VERSION_ghc(9,4,0) @@ -628,21 +691,27 @@ #if MIN_VERSION_ghc(9,11,0) import GHC.Tc.Types.CtLoc ( CtLoc(..), bumpCtLocDepth ) +#else +import GHC.Tc.Types.Constraint + ( CtLoc(..), bumpCtLocDepth ) #endif +#if MIN_VERSION_ghc(9,13,0) import GHC.Tc.Types.Constraint + ( GivenCtEvidence(..) ) +#endif +import GHC.Tc.Types.Constraint ( Ct(..), CtEvidence(..), CtFlavour(..) , QCInst(..), TcEvDest(..) , ctPred, ctLoc, ctEvidence, ctEvExpr , ctEvCoercion , ctFlavour, ctEqRel, ctOrigin - , mkNonCanonical -#if !MIN_VERSION_ghc(9,11,0) - , CtLoc(..), bumpCtLocDepth -#endif + , ctEvFlavour, ctEvPred, ctEvLoc + , mkNonCanonical, ctEvId ) import GHC.Tc.Types.Evidence ( EvBind(..), EvTerm(..), EvExpr, EvBindsVar(..) - , evCoercion, evCast, lookupEvBind, evDataConApp + , evCoercion, lookupEvBind + , mkGivenEvBind, evId ) import GHC.Tc.Types.Origin ( CtOrigin(..) ) @@ -654,6 +723,7 @@ import GHC.Tc.Utils.TcType ( TcType, TcLevel, MetaDetails, MetaInfo , isSkolemTyVar, isMetaTyVar + , nonDetCmpType ) import GHC.Tc.Utils.TcMType ( isFilledMetaTyVar_maybe, writeMetaTyVar ) @@ -673,15 +743,20 @@ ( OccName(..) , mkVarOcc, mkDataOcc, mkTyVarOcc, mkTcOcc, mkClsOcc ) -#if MIN_VERSION_ghc(9,3,0) -import GHC +#if MIN_VERSION_ghc(9,1,0) +import GHC.Driver.Env.Types ( HscEnv ) +#else +import GHC.Driver.Types + ( HscEnv ) +#endif +#if MIN_VERSION_ghc(9,3,0) +import GHC.Driver.Env.Types + ( hsc_unit_env, hsc_NC ) import GHC.Types.PkgQual ( PkgQual(..) ) import GHC.Rename.Names ( renamePkgQual ) -import GHC.Driver.Env - ( hsc_unit_env ) import GHC.Unit.Module ( unitIdString ) #elif MIN_VERSION_ghc(9,1,0) @@ -707,17 +782,16 @@ ( UniqDFM, lookupUDFM, lookupUDFM_Directly, elemUDFM ) import GHC.Types.Var ( TyVar, CoVar, TcTyVar, EvVar - , mkTyVar + , mkTyVar, DFunId ) import GHC.Utils.Outputable - ( Outputable(..), SDoc -#if !MIN_VERSION_ghc(9,2,0) - , panic, pprPanic -#endif - ) + ( Outputable(..), SDoc, text ) #if MIN_VERSION_ghc(9,2,0) import GHC.Utils.Panic ( panic, pprPanic ) +#else +import GHC.Utils.Outputable + ( panic, pprPanic ) #endif #if MIN_VERSION_ghc(9,2,0) import GHC.Unit.Finder @@ -742,22 +816,21 @@ ( HasDebugCallStack ) #endif --- transformers -import Control.Monad.IO.Class - ( MonadIO ( liftIO ) ) - -- ghc-tcplugin-api import GHC.TcPlugin.API.Internal #ifndef HAS_REWRITING import GHC.TcPlugin.API.Internal.Shim #endif --------------------------------------------------------------------------------- +-- template-haskell +import qualified Language.Haskell.TH as TH --- | Run an 'IO' computation within the plugin. -tcPluginIO :: MonadTcPlugin m => IO a -> m a -tcPluginIO = unsafeLiftTcM . liftIO +-- transformers +import Control.Monad.IO.Class + ( MonadIO ( liftIO ) ) +-------------------------------------------------------------------------------- + -- | Output some debugging information within the plugin. tcPluginTrace :: MonadTcPlugin m => String -- ^ Text at the top of the debug message. @@ -887,10 +960,8 @@ -------------------------------------------------------------------------------- -#if MIN_VERSION_ghc(9,3,0) getTopEnv :: MonadTcPlugin m => m HscEnv getTopEnv = liftTcPluginM GHC.getTopEnv -#endif -- | Obtain the current global and local type-checking environments. getEnvs :: MonadTcPlugin m => m ( TcGblEnv, TcLclEnv ) @@ -950,6 +1021,18 @@ -------------------------------------------------------------------------------- +-- | Is this a "Given" constraint? +isGiven :: CtEvidence -> Bool +isGiven ev = case ctEvFlavour ev of + Given {} -> True + _ -> False + +-- | Is this a "Wanted" constraint? +isWanted :: CtEvidence -> Bool +isWanted = not . isGiven + +-------------------------------------------------------------------------------- + -- | Create a new Wanted constraint. -- -- Requires a location (so that error messages can say where the constraint came from, @@ -967,15 +1050,19 @@ -- | Create a new Given constraint. -- -- Unlike 'newWanted', we need to supply evidence for this constraint. -newGiven :: CtLoc -> PredType -> EvExpr -> TcPluginM Solve CtEvidence +newGiven :: CtLoc -> PredType -> EvTerm -> TcPluginM Solve CtEvidence newGiven loc pty evtm = do -#if HAS_REWRITING - tc_evbinds <- askEvBinds - liftTcPluginM $ GHC.newGiven tc_evbinds loc pty evtm -#else - liftTcPluginM $ GHC.newGiven loc pty evtm + new_ev <- newEvVar pty + setEvBind $ mkGivenEvBind new_ev evtm + return $ + CtGiven +#if MIN_VERSION_ghc(9,13,0) + $ GivenCt #endif - + { ctev_pred = pty + , ctev_evar = new_ev + , ctev_loc = loc + } -- | Obtain the 'CtLoc' from a 'RewriteEnv'. -- @@ -1078,7 +1165,9 @@ -> TcType -- ^ The type that the type family application reduces to -> Reduction mkTyFamAppReduction str role deps tc args ty = - Reduction ( mkPluginUnivCo str role deps ( mkTyConApp tc args ) ty ) ty + Reduction + ( mkPluginUnivCo str role deps ( mkTyConApp tc args ) ty ) + ty -------------------------------------------------------------------------------- @@ -1145,6 +1234,123 @@ setInertSet :: InertSet -> TcS () setInertSet = setTcSInerts +#endif + +-------------------------------------------------------------------------------- + +-- | Resolve a @template-haskell@ 'TH.Name' to a GHC 'Name'. +-- +-- Especially useful in conjunction with @TemplateHaskellQuotes@, e.g. to +-- look up the 'Name' of the @Maybe@ type constructor, you can do: +-- +-- > lookupName ''Maybe +-- +-- @since 0.15.0.0 +lookupTHName :: ( Monad (TcPluginM s), MonadTcPlugin (TcPluginM s) ) + => TH.Name -> TcPluginM s Name +lookupTHName thNm = do + hscEnv <- getTopEnv + mbNm <- + liftIO $ + thNameToGhcNameIO +#if MIN_VERSION_ghc(9,6,0) + (hsc_NC hscEnv) +#else + hscEnv +#endif + thNm + case mbNm of + Just nm -> + return nm + Nothing -> + pprPanic "lookupTHName: lookup failed" (text $ show thNm) + +-------------------------------------------------------------------------------- + +-- | Apply an instance dictionary function to type and value arguments. +-- +-- NB: different from @evDFunApp@ defined in GHC, as this function returns +-- an @EvExpr@ rather than an @EvTerm@. +evDFunApp :: DFunId -> [Type] -> [EvExpr] -> EvExpr +evDFunApp df tys ets = Var df `mkTyApps` tys `mkApps` ets + +-- | Apply a data constructor to type and value arguments. +-- +-- NB: different from @evDataConApp@ defined in GHC, as this function returns +-- an @EvExpr@ rather than an @EvTerm@. +evDataConApp :: DataCon -> [Type] -> [EvExpr] -> EvExpr +evDataConApp dc tys ets = evDFunApp (dataConWrapId dc) tys ets + +-- | Cast an evidence expression by a coercion. +-- +-- NB: different from @evCast@ defined in GHC, as this function returns +-- an @EvExpr@ rather than an @EvTerm@. +evCast :: EvExpr -> Coercion -> EvExpr +evCast et co | isReflCo co = et + | otherwise = Cast et co + +-------------------------------------------------------------------------------- + +natKind, symbolKind, charKind :: Type +natKind = +#if MIN_VERSION_ghc(9,1,0) + naturalTy +#else + typeNatKind +#endif +symbolKind = typeSymbolKind +charKind = charTy + +-------------------------------------------------------------------------------- + +-- | Is this a primitive (unboxed) equality type, i.e. one of: +-- +-- - @~#@ (heterogeneous nominal unboxed equality), +-- - @~R#@ (heterogeneous representational unboxed equality). +-- +-- NB: returns @False@ for **boxed** equalities such as @(~)@, @(~~)@ and @Coercible@. +-- If you want to detect those, use 'isEqClassPred'. +isEqPred :: PredType -> Bool +isEqPred pty + | Just tc <- tyConAppTyCon_maybe pty + = tc `hasKey` eqPrimTyConKey || tc `hasKey` eqReprPrimTyConKey + | otherwise + = False + +-- | Is this a boxed equality type, i.e. one of: +-- +-- - @(~)@ (homogeneous nominal boxed equality), +-- - @(~~)@ (heterogeneous nominal boxed equality), +-- - @Coercible@ (homogeneous boxed representational equality). +isEqClassPred :: PredType -> Bool +isEqClassPred pty + | Just tc <- tyConAppTyCon_maybe pty + , Just cls <- tyConClass_maybe tc + = cls `hasKey` heqTyConKey + || cls `hasKey` eqTyConKey + || cls `hasKey` coercibleTyConKey + | otherwise + = False + +-------------------------------------------------------------------------------- + +#if !MIN_VERSION_ghc(9,6,0) +thNameToGhcNameIO :: HscEnv -> TH.Name -> IO (Maybe Name) +thNameToGhcNameIO hscEnv th_name + = do { names <- mapMaybeM do_lookup (thRdrNameGuesses th_name) + ; return (listToMaybe names) } + where + do_lookup rdr_name + | Just n <- isExact_maybe rdr_name + = return $ if isExternalName n then Just n else Nothing + | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name +#if MIN_VERSION_ghc(9,3,0) + = Just <$> lookupNameCache (hsc_NC hscEnv) rdr_mod rdr_occ +#else + = Just <$> lookupOrigIO hscEnv rdr_mod rdr_occ +#endif + | otherwise + = return Nothing #endif --------------------------------------------------------------------------------
src/GHC/TcPlugin/API/Internal.hs view
@@ -69,6 +69,8 @@ ( TypeError, ErrorMessage(..) ) -- transformers +import Control.Monad.IO.Class + ( MonadIO ( liftIO ) ) import Control.Monad.Trans.Reader ( ReaderT(..) ) @@ -464,6 +466,10 @@ adaptUserStop :: ( userDefs -> TcPluginM Stop () ) -> TcPluginDefs userDefs -> GHC.TcPluginM () adaptUserStop userStop ( TcPluginDefs { tcPluginUserDefs } ) = tcPluginStopM $ userStop tcPluginUserDefs + +-- | @since 0.15.0.0 +instance ( Monad ( TcPluginM s ), MonadTcPlugin ( TcPluginM s ) ) => MonadIO ( TcPluginM s ) where + liftIO = unsafeLiftTcM . liftIO -- | Monads for type-checking plugins which are able to emit new constraints -- and throw errors.