From 208eb90763c8878ba89dd46954ef222888dc187d Mon Sep 17 00:00:00 2001 From: sheaf Date: Tue, 1 Sep 2026 17:07:29 +0200 Subject: [PATCH 1/2] Preliminary GHC 10.2 support --- changelog.md | 15 ++++ ghc-tcplugin-api.cabal | 16 ++-- src/GHC/Builtins.hs | 129 +++++++++++++++++++++++++++++++ src/GHC/TcPlugin/API.hs | 34 ++++---- src/GHC/TcPlugin/API/Internal.hs | 72 ++++++++++------- 5 files changed, 211 insertions(+), 55 deletions(-) create mode 100644 src/GHC/Builtins.hs diff --git a/changelog.md b/changelog.md index 1a72571..f415307 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,18 @@ +# Version 0.20.0.0 (2026-09-01) + +- Preliminary support for GHC 10.2 (with the known-entities refactor). + +- The re-exports of `GHC.Builtin.Names`, `GHC.Builtin.Types` and + `GHC.Builtin.Types.Prim` have been replaced by a single umbrella helper + module, `GHC.Builtins`. Remarks: + + - GHC 10.2 no longer defines static `Name`s for known-key entities. Instead, + these need to be resolved at runtime. Accordingly, `GHC.Builtins` + exports `KnownKey` uniques such as `errorMessageTypeErrorFamKey` on + GHC >= 10.2, instead of `Name`s such as `errorMessageTypeErrorFamName`. + + - The `MonadThings` class has been removed. Use `tcLookupTyCon`, + `tcLookupDataCon` etc instead. # Version 0.19.0.0 (2026-05-12) diff --git a/ghc-tcplugin-api.cabal b/ghc-tcplugin-api.cabal index 63747a1..3bce8be 100644 --- a/ghc-tcplugin-api.cabal +++ b/ghc-tcplugin-api.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: ghc-tcplugin-api -version: 0.19.0.0 +version: 0.20.0.0 synopsis: An API for type-checker plugins. license: BSD-3-Clause build-type: Simple @@ -39,11 +39,11 @@ library containers >= 0.6 && < 0.9, ghc - >= 8.8 && < 10.1, + >= 8.8 && < 10.3, transformers >= 0.5 && < 0.7, template-haskell - >= 2.15 && < 2.26, + >= 2.15 && < 3, default-language: Haskell2010 @@ -64,13 +64,12 @@ library GHC.TcPlugin.API.Names, GHC.TcPlugin.API.TyConSubst, - GHC.TcPlugin.API.Internal + GHC.TcPlugin.API.Internal, + + GHC.Builtins reexported-modules: - GHC.Builtin.Names - , GHC.Builtin.Types - , GHC.Builtin.Types.Prim - , GHC.Core.Make + GHC.Core.Make , GHC.Plugins , GHC.Types.Unique.DFM , GHC.Types.Unique.FM @@ -100,6 +99,7 @@ library , PrelNames as GHC.Builtin.Names , TysWiredIn as GHC.Builtin.Types + , TcTypeNats as GHC.Builtin.Types.Literals , TysPrim as GHC.Builtin.Types.Prim , CoreSyn as GHC.Core diff --git a/src/GHC/Builtins.hs b/src/GHC/Builtins.hs new file mode 100644 index 0000000..0df64d0 --- /dev/null +++ b/src/GHC/Builtins.hs @@ -0,0 +1,129 @@ +{-# LANGUAGE CPP #-} + +-- | Helper umbrella re-exports of various known entities to GHC: known-key +-- uniques, wired-in types. +module GHC.Builtins + ( -- * Known-key uniques + hasKey + , eqTyConKey, heqTyConKey, coercibleTyConKey + , eqPrimTyConKey, eqReprPrimTyConKey, eqPhantPrimTyConKey + + -- * Custom type errors (prefer using 'GHC.TcPlugin.API.mkTcPluginErrorTy') +#if MIN_VERSION_ghc(10,1,0) + , errorMessageTypeErrorFamKey + , typeErrorTextDataConKey, typeErrorShowTypeDataConKey + , typeErrorAppendDataConKey, typeErrorVAppendDataConKey +#else + , errorMessageTypeErrorFamName + , typeErrorTextDataConName, typeErrorShowTypeDataConName + , typeErrorAppendDataConName, typeErrorVAppendDataConName +#endif + + -- * Equality and coercions + , eqTyCon, heqTyCon, coercibleTyCon + , eqPrimTyCon, eqReprPrimTyCon, eqPhantPrimTyCon + , eqClass, heqClass, coercibleClass + , eqDataCon, heqDataCon, coercibleDataCon +#if MIN_VERSION_ghc(8,10,0) + , equalityTyCon +#endif + + -- * Kinds + , liftedTypeKind, constraintKind, typeSymbolKind + , unboxedTupleKind, unboxedSumKind + , liftedTypeKindTyCon, constraintKindTyCon, tYPETyCon + , anyTy, anyTyCon, anyTypeOfKind +#if MIN_VERSION_ghc(8,10,0) + , typeToTypeKind +#endif +#if MIN_VERSION_ghc(9,1,0) + , unliftedTypeKind +#endif +#if MIN_VERSION_ghc(9,3,0) + , zeroBitTypeKind +#endif +#if MIN_VERSION_ghc(9,5,0) + , tYPEKind, cONSTRAINTKind, cONSTRAINTTyCon, fUNTyCon +#endif + + -- * Runtime representations, levities and multiplicities + , runtimeRepTy, runtimeRepTyCon, liftedRepTy +#if MIN_VERSION_ghc(9,0,0) + , multiplicityTy, multiplicityTyCon + , manyDataCon, oneDataCon, manyDataConTy, oneDataConTy +#endif +#if MIN_VERSION_ghc(9,1,0) + , unliftedRepTy, boxedRepDataConTyCon, levityTyCon + , liftedDataConTy, unliftedDataConTy + , liftedDataConTyCon, unliftedDataConTyCon +#endif +#if MIN_VERSION_ghc(9,3,0) + , levityTy, zeroBitRepTy +#endif + + -- * Wired-in types + , unitTy, unitTyCon, unitDataCon, unitDataConId + , boolTy, boolTyCon, trueDataCon, falseDataCon + , promotedTrueDataCon, promotedFalseDataCon + , orderingTyCon, promotedLTDataCon, promotedEQDataCon, promotedGTDataCon + , charTy, charTyCon, charDataCon + , intTy, intTyCon, intDataCon + , wordTy, wordTyCon, wordDataCon + , floatTy, floatTyCon, doubleTy, doubleTyCon + , stringTy + , listTyCon, nilDataCon, consDataCon + , promotedNilDataCon, promotedConsDataCon + , maybeTyCon, justDataCon, nothingDataCon + , promotedJustDataCon, promotedNothingDataCon +#if MIN_VERSION_ghc(9,0,0) + , integerTy, integerTyCon, naturalTy, naturalTyCon +#endif +#if !MIN_VERSION_ghc(9,1,0) + , typeNatKind +#endif + + -- * Tuples and sums + , tupleTyCon, tupleDataCon, promotedTupleDataCon + , sumTyCon, sumDataCon + , mkTupleTy, mkBoxedTupleTy, mkSumTy + , mkListTy, mkPromotedListTy +#if MIN_VERSION_ghc(8,10,0) + , mkTupleTy1 +#endif +#if MIN_VERSION_ghc(9,1,0) + , cTupleTyCon, cTupleDataCon + , mkMaybeTy, mkPromotedMaybeTy, mkPromotedPairTy +#endif +#if MIN_VERSION_ghc(9,5,0) + , mkConstraintTupleTy +#endif + + -- * Type-level literals + , typeNatTyCons, typeNatCoAxiomRules + , typeNatAddTyCon, typeNatSubTyCon, typeNatMulTyCon, typeNatExpTyCon + , typeNatDivTyCon, typeNatModTyCon, typeNatLogTyCon, typeNatCmpTyCon + , typeSymbolCmpTyCon, typeSymbolAppendTyCon, typeSymbolKindCon +#if MIN_VERSION_ghc(9,1,0) + , typeConsSymbolTyCon, typeUnconsSymbolTyCon + , typeCharCmpTyCon, typeCharToNatTyCon, typeNatToCharTyCon +#endif + + -- * Primitive types + , intPrimTy, wordPrimTy, charPrimTy, floatPrimTy, doublePrimTy + , realWorldTy, realWorldTyCon, realWorldStatePrimTy + , mkStatePrimTy, mkProxyPrimTy, proxyPrimTyCon + ) + where + +-- ghc +#if MIN_VERSION_ghc(10,1,0) +import GHC.Builtin.KnownKeys +import GHC.Builtin.WiredIn.Prim +import GHC.Builtin.WiredIn.TypeLits +import GHC.Builtin.WiredIn.Types +#else +import GHC.Builtin.Names +import GHC.Builtin.Types +import GHC.Builtin.Types.Literals +import GHC.Builtin.Types.Prim +#endif diff --git a/src/GHC/TcPlugin/API.hs b/src/GHC/TcPlugin/API.hs index 3f993f6..42d2a0b 100644 --- a/src/GHC/TcPlugin/API.hs +++ b/src/GHC/TcPlugin/API.hs @@ -511,7 +511,6 @@ module GHC.TcPlugin.API -- | == Names , Name, OccName, TyThing, TcTyThing - , MonadThings(..) , Class(classTyCon), DataCon, TyCon, Id , FastString @@ -559,25 +558,6 @@ import Data.Maybe -- 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 ) -import GHC.Builtin.Types.Prim - ( intPrimTy ) -#endif import GHC.Core ( CoreBndr, CoreExpr, Expr(..), mkTyApps, mkApps ) import GHC.Core.Class @@ -885,6 +865,20 @@ import GHC.Utils.Misc ( filterOut ) -- ghc-tcplugin-api +import GHC.Builtins + ( hasKey + , eqPrimTyConKey, eqReprPrimTyConKey + , heqTyConKey, eqTyConKey, coercibleTyConKey + , typeSymbolKind, charTy +#if MIN_VERSION_ghc(9,1,0) + , naturalTy +#else + , typeNatKind +#endif +#if !MIN_VERSION_ghc(9,0,0) + , intDataCon, intPrimTy +#endif + ) import GHC.TcPlugin.API.Internal #ifndef HAS_REWRITING import GHC.TcPlugin.API.Internal.Shim diff --git a/src/GHC/TcPlugin/API/Internal.hs b/src/GHC/TcPlugin/API/Internal.hs index a62c69d..46d765e 100644 --- a/src/GHC/TcPlugin/API/Internal.hs +++ b/src/GHC/TcPlugin/API/Internal.hs @@ -51,7 +51,6 @@ module GHC.TcPlugin.API.Internal , TcPluginM(..) , TcPluginErrorMessage(..) , TcPluginRewriter - , MonadThings(..) , askRewriteEnv , askDeriveds , askEvBinds @@ -75,17 +74,6 @@ import Control.Monad.Trans.Reader ( ReaderT(..) ) -- ghc -import qualified GHC.Builtin.Names - as GHC.TypeLits - ( errorMessageTypeErrorFamName - , typeErrorTextDataConName - , typeErrorAppendDataConName - , typeErrorVAppendDataConName - , typeErrorShowTypeDataConName - ) -import qualified GHC.Builtin.Types - as GHC - ( constraintKind ) import qualified GHC.Core.DataCon as GHC ( promoteDataCon ) @@ -104,6 +92,11 @@ import qualified GHC.Data.FastString import qualified GHC.Tc.Plugin as GHC ( tcLookupDataCon, tcLookupTyCon ) +#if MIN_VERSION_ghc(10,1,0) +import qualified GHC.Tc.Utils.Env + as GHC + ( rnLookupKnownKeyName ) +#endif import qualified GHC.Tc.Types as GHC ( TcM, TcPlugin(..), TcPluginM @@ -134,12 +127,7 @@ import qualified GHC.Tc.Types.Evidence import qualified GHC.Types.Unique.FM as GHC ( UniqFM ) -#if MIN_VERSION_ghc(9,1,0) -import GHC.Types.TyThing - ( MonadThings(..) ) -#else -import GHC.Driver.Types - ( MonadThings(..) ) +#if !MIN_VERSION_ghc(9,1,0) import GHC.Tc.Types.Constraint ( ctEvidence, ctEvId, isDerived ) import GHC.Types.Var.Env @@ -150,6 +138,26 @@ import GHC.Tc.Plugin #endif -- ghc-tcplugin-api +import qualified GHC.Builtins + as GHC + ( constraintKind ) +import qualified GHC.Builtins + as GHC.TypeError +#if MIN_VERSION_ghc(10,1,0) + ( errorMessageTypeErrorFamKey + , typeErrorTextDataConKey + , typeErrorAppendDataConKey + , typeErrorVAppendDataConKey + , typeErrorShowTypeDataConKey + ) +#else + ( errorMessageTypeErrorFamName + , typeErrorTextDataConName + , typeErrorAppendDataConName + , typeErrorVAppendDataConName + , typeErrorShowTypeDataConName + ) +#endif #ifndef HAS_REWRITING import GHC.TcPlugin.API.Internal.Shim ( TcPluginSolveResult, TcPluginRewriteResult(..) @@ -622,10 +630,6 @@ mkTcPluginErrorTy msg = do errorMsgTy = interpretErrorMessage builtinDefs msg pure $ GHC.mkTyConApp typeErrorTyCon [ GHC.constraintKind, errorMsgTy ] -instance ( Monad ( TcPluginM s ), MonadTcPlugin ( TcPluginM s ) ) - => MonadThings ( TcPluginM s ) where - lookupThing = unsafeLiftTcM . lookupThing - -------------------------------------------------------------------------------- -- Private types and functions. -- Not exposed at all, even from the internal module. @@ -647,11 +651,25 @@ data TcPluginDefs s initBuiltinDefs :: GHC.TcPluginM BuiltinDefs initBuiltinDefs = do - typeErrorTyCon <- GHC.tcLookupTyCon GHC.TypeLits.errorMessageTypeErrorFamName - textTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon GHC.TypeLits.typeErrorTextDataConName - showTypeTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon GHC.TypeLits.typeErrorShowTypeDataConName - concatTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon GHC.TypeLits.typeErrorAppendDataConName - vcatTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon GHC.TypeLits.typeErrorVAppendDataConName +#if MIN_VERSION_ghc(10,1,0) + let lookupBuiltin = GHC.unsafeTcPluginTcM . GHC.rnLookupKnownKeyName + typeErrorName <- lookupBuiltin GHC.TypeError.errorMessageTypeErrorFamKey + textName <- lookupBuiltin GHC.TypeError.typeErrorTextDataConKey + showTypeName <- lookupBuiltin GHC.TypeError.typeErrorShowTypeDataConKey + concatName <- lookupBuiltin GHC.TypeError.typeErrorAppendDataConKey + vcatName <- lookupBuiltin GHC.TypeError.typeErrorVAppendDataConKey +#else + let typeErrorName = GHC.TypeError.errorMessageTypeErrorFamName + textName = GHC.TypeError.typeErrorTextDataConName + showTypeName = GHC.TypeError.typeErrorShowTypeDataConName + concatName = GHC.TypeError.typeErrorAppendDataConName + vcatName = GHC.TypeError.typeErrorVAppendDataConName +#endif + typeErrorTyCon <- GHC.tcLookupTyCon typeErrorName + textTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon textName + showTypeTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon showTypeName + concatTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon concatName + vcatTyCon <- GHC.promoteDataCon <$> GHC.tcLookupDataCon vcatName pure ( BuiltinDefs { .. } ) interpretErrorMessage :: BuiltinDefs -> TcPluginErrorMessage -> GHC.PredType From a79f492d2137007b5c2efe46f48d6ca7c4abe688 Mon Sep 17 00:00:00 2001 From: sheaf Date: Tue, 1 Sep 2026 17:16:56 +0200 Subject: [PATCH 2/2] Update CI config --- .github/workflows/ci.yml | 80 ++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73c6260..286c97f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,28 +5,40 @@ on: pull_request: push: branches: [main] + workflow_dispatch: + +permissions: + contents: read + +# Don't keep running superseded builds of a branch, but never cancel main. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: cabal: name: ${{ matrix.cfg.os }} / ghc ${{ matrix.cfg.ghc }} runs-on: ${{ matrix.cfg.os }} strategy: + # Always run the whole matrix so that we get all errors at once. + fail-fast: false matrix: cfg: - - { os: ubuntu-latest , ghc: "9.12.2" } - - { os: ubuntu-latest , ghc: "9.10.2" } - - { os: ubuntu-latest , ghc: "9.8.4" } - - { os: ubuntu-latest , ghc: "9.6.7" } - - { os: ubuntu-latest , ghc: "9.4.8" } - - { os: ubuntu-latest , ghc: "9.2.8" } - - { os: ubuntu-latest , ghc: "9.0.2" } - - { os: ubuntu-latest , ghc: "8.10.7" } - - { os: ubuntu-latest , ghc: "8.8.4" } - - { os: macOS-latest , ghc: "9.12.2" } - - { os: windows-latest , ghc: "9.12.2" } + - { os: ubuntu-latest , ghc: "9.14.1" , examples: true , docs: true } + - { os: ubuntu-latest , ghc: "9.12.4" , examples: true , eqsat: true } # only build eqsat on 9.12 for now + - { os: ubuntu-latest , ghc: "9.10.3" , examples: true } + - { os: ubuntu-latest , ghc: "9.8.4" , examples: true } + - { os: ubuntu-latest , ghc: "9.6.7" , examples: true } + - { os: ubuntu-latest , ghc: "9.4.8" , examples: true } + - { os: ubuntu-latest , ghc: "9.2.8" , examples: true } + - { os: ubuntu-latest , ghc: "9.0.2" , examples: true } + - { os: ubuntu-latest , ghc: "8.10.7" , examples: true } + - { os: ubuntu-latest , ghc: "8.8.4" } # skip examples: needs StandaloneKindSignatures + - { os: macOS-latest , ghc: "9.12.4" , examples: true } + - { os: windows-latest , ghc: "9.14.1" , examples: true } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Set up GHC ${{ matrix.cfg.ghc }} uses: haskell-actions/setup@v2 @@ -38,46 +50,26 @@ jobs: cabal-update: true - name: Configure the build - run: | - cabal configure --disable-documentation - cabal build all --dry-run - # The last step generates dist-newstyle/cache/plan.json for the cache key. - - - name: Restore cached dependencies - uses: actions/cache/restore@v4 - id: cache - env: - key: ${{ runner.os }}-ghc-${{ steps.setup.outputs.ghc-version }}-cabal-${{ steps.setup.outputs.cabal-version }} - with: - path: ${{ steps.setup.outputs.cabal-store }} - key: ${{ env.key }}-plan-${{ hashFiles('**/plan.json') }} - restore-keys: ${{ env.key }}- - - - name: Install dependencies - # If we had an exact cache hit, the dependencies will be up to date. - if: steps.cache.outputs.cache-hit != 'true' - run: cabal build all --only-dependencies - - # Cache dependencies already here, so that we do not have to rebuild them should the subsequent steps fail. - - name: Save cached dependencies - uses: actions/cache/save@v4 - # If we had an exact cache hit, trying to save the cache would error because of key clash. - if: steps.cache.outputs.cache-hit != 'true' - with: - path: ${{ steps.setup.outputs.cabal-store }} - key: ${{ steps.cache.outputs.cache-primary-key }} + run: cabal configure --disable-documentation - name: Build ghc-tcplugin-api run: cabal build ghc-tcplugin-api + - name: Build the documentation + if: matrix.cfg.docs + run: cabal haddock ghc-tcplugin-api + - name: Build and lint System F example - # Skip this test on GHC 8.8.4: we need StandaloneKindSignatures. - if: matrix.cfg.ghc != '8.8.4' + if: matrix.cfg.examples working-directory: ./examples/SystemF run: cabal build system-f + - name: Build and lint rewriter plugin example + if: matrix.cfg.examples + working-directory: ./examples/RewriterPlugin + run: cabal build lib:RewriterPlugin + - name: Build and lint equality saturation example - # Only run this test on 9.12 for now. - if: matrix.cfg.ghc == '9.12.2' + if: matrix.cfg.eqsat working-directory: ./examples/EqSat run: cabal build eq-sat