packages feed

ghc-tcplugin-api 0.3.1.0 → 0.4.0.0

raw patch · 7 files changed

+836/−56 lines, 7 filesdep ~basedep ~ghcPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, ghc

API changes (from Hackage documentation)

- GHC.TcPlugin.API: TcPluginContradiction :: [Ct] -> TcPluginSolveResult
- GHC.TcPlugin.API: TcPluginOk :: [(EvTerm, Ct)] -> [Ct] -> TcPluginSolveResult
- GHC.TcPlugin.API: data () => CanEqLHS
- GHC.TcPlugin.API: mkInvisForAllTys :: [InvisTVBinder] -> Type -> Type
+ GHC.TcPlugin.API: TcPluginSolveResult :: [Ct] -> [(EvTerm, Ct)] -> [Ct] -> TcPluginSolveResult
+ GHC.TcPlugin.API: [tcPluginInsolubleCts] :: TcPluginSolveResult -> [Ct]
+ GHC.TcPlugin.API: pattern TcPluginContradiction :: [Ct] -> TcPluginSolveResult
+ GHC.TcPlugin.API: pattern TcPluginOk :: [(EvTerm, Ct)] -> [Ct] -> TcPluginSolveResult
+ GHC.TcPlugin.API.Names: Generically1 :: f a -> Generically1 f a
+ GHC.TcPlugin.API.Names: Named :: NameResolution
+ GHC.TcPlugin.API.Names: Qualified :: String -> ModuleName -> Maybe FastString -> QualifiedName thing
+ GHC.TcPlugin.API.Names: Resolved :: NameResolution
+ GHC.TcPlugin.API.Names: [module'] :: QualifiedName thing -> ModuleName
+ GHC.TcPlugin.API.Names: [name] :: QualifiedName thing -> String
+ GHC.TcPlugin.API.Names: [package] :: QualifiedName thing -> Maybe FastString
+ GHC.TcPlugin.API.Names: class Lookupable a
+ GHC.TcPlugin.API.Names: class ResolveNames f
+ GHC.TcPlugin.API.Names: data NameResolution
+ GHC.TcPlugin.API.Names: data Promoted thing
+ GHC.TcPlugin.API.Names: data QualifiedName thing
+ GHC.TcPlugin.API.Names: instance (GHC.Generics.Generic (f 'GHC.TcPlugin.API.Names.Named), GHC.Generics.Generic (f 'GHC.TcPlugin.API.Names.Resolved), GHC.TcPlugin.API.Names.GTraversableC GHC.TcPlugin.API.Names.ResolveName (GHC.Generics.Rep (f 'GHC.TcPlugin.API.Names.Named)) (GHC.Generics.Rep (f 'GHC.TcPlugin.API.Names.Resolved))) => GHC.TcPlugin.API.Names.ResolveNames (GHC.TcPlugin.API.Names.Generically1 f)
+ GHC.TcPlugin.API.Names: instance (GHC.TcPlugin.API.Names.GTraversableC c l l', GHC.TcPlugin.API.Names.GTraversableC c r r') => GHC.TcPlugin.API.Names.GTraversableC c (l GHC.Generics.:*: r) (l' GHC.Generics.:*: r')
+ GHC.TcPlugin.API.Names: instance (GHC.TcPlugin.API.Names.GTraversableC c l l', GHC.TcPlugin.API.Names.GTraversableC c r r') => GHC.TcPlugin.API.Names.GTraversableC c (l GHC.Generics.:+: r) (l' GHC.Generics.:+: r')
+ GHC.TcPlugin.API.Names: instance (a GHC.Types.~ GHC.TcPlugin.API.Names.Wear 'GHC.TcPlugin.API.Names.Named (GHC.TcPlugin.API.Names.UnwearNamed a), b GHC.Types.~ GHC.TcPlugin.API.Names.Wear 'GHC.TcPlugin.API.Names.Resolved (GHC.TcPlugin.API.Names.UnwearNamed a), GHC.TcPlugin.API.Names.Lookupable (GHC.TcPlugin.API.Names.UnwearNamed a)) => GHC.TcPlugin.API.Names.ResolveName a b
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.GTraversableC c GHC.Generics.U1 GHC.Generics.U1
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.GTraversableC c GHC.Generics.V1 GHC.Generics.V1
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.GTraversableC c s t => GHC.TcPlugin.API.Names.GTraversableC c (GHC.Generics.M1 i m s) (GHC.Generics.M1 i m t)
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.Lookupable (GHC.TcPlugin.API.Names.Promoted GHC.Core.DataCon.DataCon)
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.Lookupable GHC.Core.Class.Class
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.Lookupable GHC.Core.DataCon.DataCon
+ GHC.TcPlugin.API.Names: instance GHC.TcPlugin.API.Names.Lookupable GHC.Core.TyCon.TyCon
+ GHC.TcPlugin.API.Names: instance c a b => GHC.TcPlugin.API.Names.GTraversableC c (GHC.Generics.Rec0 a) (GHC.Generics.Rec0 b)
+ GHC.TcPlugin.API.Names: instance forall k (f :: k -> *) (a :: k). GHC.Generics.Generic (f a) => GHC.Generics.Generic (GHC.TcPlugin.API.Names.Generically1 f a)
+ GHC.TcPlugin.API.Names: lookup :: (Lookupable a, MonadTcPlugin m) => Name -> m (Wear Resolved a)
+ GHC.TcPlugin.API.Names: mkOccName :: Lookupable a => String -> OccName
+ GHC.TcPlugin.API.Names: newtype Generically1 f a
+ GHC.TcPlugin.API.Names: resolveNames :: (MonadTcPlugin m, ResolveNames f) => f Named -> m (f Resolved)
+ GHC.TcPlugin.API.Names: type family Wear n thing
- GHC.TcPlugin.API: class Monad m => MonadTcPlugin m
+ GHC.TcPlugin.API: class (Monad m, (forall x y. Coercible x y => Coercible (m x) (m y))) => MonadTcPlugin m
- GHC.TcPlugin.API.Internal: class Monad m => MonadTcPlugin m
+ GHC.TcPlugin.API.Internal: class (Monad m, (forall x y. Coercible x y => Coercible (m x) (m y))) => MonadTcPlugin m

Files

changelog.md view
@@ -1,4 +1,16 @@ 
+# Version 0.4.0.0 (2021-08-24)
+
+- Adapt to GHC 9.4 changes in the `TcPluginSolveResult` datatype:
+  are now able to solve and emit constraints even when reporting
+  a contradiction. This can help with error messages.
+  Unfortunately these extra constraints will be dropped in versions
+  of GHC prior to 9.4.
+
+- Add a utility module for name resolution using constrained traversals.
+
+- Add compatibility for GHC 8.10.
+
 # Version 0.3.1.0 (2021-08-09)
 
 Ensure that the coercions stored in `Reduction`s are always
ghc-tcplugin-api.cabal view
@@ -1,6 +1,6 @@ cabal-version:  3.0
 name:           ghc-tcplugin-api
-version:        0.3.1.0
+version:        0.4.0.0
 synopsis:       An API for type-checker plugins.
 license:        BSD-3-Clause
 build-type:     Simple
@@ -33,9 +33,9 @@ 
   build-depends:
     base
-      >= 4.15.0 && < 4.18,
+      >= 4.14.0 && < 4.18,
     ghc
-      >= 9.0    && < 9.5,
+      >= 8.10   && < 9.5,
     transformers
       >= 0.5    && < 0.6,
 
@@ -55,6 +55,7 @@ 
   exposed-modules:
     GHC.TcPlugin.API,
+    GHC.TcPlugin.API.Names,
     GHC.TcPlugin.API.Internal
 
   if impl(ghc >= 9.3.0)
@@ -66,3 +67,76 @@ 
   if impl(ghc < 9.5.0)
     cpp-options: -DHAS_DERIVEDS
+
+  -- Compatibility for versions of GHC prior to 9.0.
+  if impl(ghc < 9.0)
+
+    reexported-modules:
+        GHC.Core.Make
+      , GHC.Plugins
+      , GHC.Types.Unique.DFM
+      , GHC.Types.Unique.FM
+      , GHC.Utils.Outputable
+
+    mixins:
+      ghc
+        ( GHC        as GHC
+
+        , PrelNames  as GHC.Builtin.Names
+        , TysWiredIn as GHC.Builtin.Types
+
+        , CoreSyn    as GHC.Core
+        , CoAxiom    as GHC.Core.Coercion.Axiom
+        , Coercion   as GHC.Core.Coercion
+        , Class      as GHC.Core.Class
+        , DataCon    as GHC.Core.DataCon
+        , FamInstEnv as GHC.Core.FamInstEnv
+        , InstEnv    as GHC.Core.InstEnv
+        , MkCore     as GHC.Core.Make
+        , TyCoRep    as GHC.Core.TyCo.Rep
+        , TyCon      as GHC.Core.TyCon
+        , Type       as GHC.Core.Type
+
+        , FastString as GHC.Data.FastString
+        , Pair       as GHC.Data.Pair
+
+        , Finder     as GHC.Driver.Finder
+        , DynFlags   as GHC.Driver.Session
+        , HscTypes   as GHC.Driver.Types
+
+        , GhcPlugins as GHC.Plugins
+
+        , TcPluginM  as GHC.Tc.Plugin
+        , TcSMonad   as GHC.Tc.Solver.Monad
+        , TcRnTypes  as GHC.Tc.Types
+        , TcEvidence as GHC.Tc.Types.Evidence
+        , TcRnMonad  as GHC.Tc.Utils.Monad
+        , TcType     as GHC.Tc.Utils.TcType
+
+        , Name       as GHC.Types.Name
+        , OccName    as GHC.Types.Name.Occurrence
+        , Unique     as GHC.Types.Unique
+        , UniqDFM    as GHC.Types.Unique.DFM
+        , UniqFM     as GHC.Types.Unique.FM
+        , Var        as GHC.Types.Var
+        , VarEnv     as GHC.Types.Var.Env
+        , VarSet     as GHC.Types.Var.Set
+
+        , Module     as GHC.Unit.Module
+        , Module     as GHC.Unit.Module.Name
+        , Module     as GHC.Unit.Types
+
+        , Util       as GHC.Utils.Misc
+        , TcRnMonad  as GHC.Utils.Monad
+        , Outputable as GHC.Utils.Outputable
+        , Panic      as GHC.Utils.Panic
+        )
+
+    if impl(ghc > 8.10)
+
+      mixins:
+        ghc
+          ( Predicate  as GHC.Core.Predicate
+          , Constraint as GHC.Tc.Types.Constraint
+          , TcOrigin   as GHC.Tc.Types.Origin
+          )
src/GHC/TcPlugin/API.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE PatternSynonyms #-}
-{-# LANGUAGE StandaloneKindSignatures #-}
 {-# LANGUAGE UndecidableInstances #-}
 
 {-|
@@ -361,14 +360,18 @@ 
     -- ** Function types
 
-  , AnonArgFlag(..), Mult
+  , AnonArgFlag(..)
   , mkFunTy, mkVisFunTy, mkInvisFunTy, mkVisFunTys
-  , mkForAllTy, mkForAllTys, mkInvisForAllTys
+  , mkForAllTy, mkForAllTys
   , mkPiTy, mkPiTys
+
+#if MIN_VERSION_ghc(9,0,0)
+  , Mult
   , mkFunTyMany
   , mkScaledFunTy
   , mkVisFunTyMany, mkVisFunTysMany
   , mkInvisFunTyMany, mkInvisFunTysMany
+#endif
 
     -- ** Zonking
 
@@ -415,9 +418,6 @@   , Pred(..), EqRel(..), FunDep, CtFlavour
   , Ct, CtLoc, CtEvidence, CtOrigin
   , QCInst
-#if MIN_VERSION_ghc(9,2,0)
-  , CanEqLHS
-#endif
   , Type, PredType
   , InstEnvs, TcLevel
 
@@ -472,15 +472,18 @@   ( Type, PredType, Kind
   , Coercion(..), CoercionHole(..)
   , UnivCoProvenance(..)
-  , AnonArgFlag(..), Mult
+  , AnonArgFlag(..)
   , mkTyVarTy, mkTyVarTys
   , mkFunTy, mkVisFunTy, mkInvisFunTy, mkVisFunTys
-  , mkForAllTy, mkForAllTys, mkInvisForAllTys
+  , mkForAllTy, mkForAllTys
   , mkPiTy, mkPiTys
+#if MIN_VERSION_ghc(9,0,0)
+  , Mult
   , mkFunTyMany
   , mkScaledFunTy
   , mkVisFunTyMany, mkVisFunTysMany
   , mkInvisFunTyMany, mkInvisFunTysMany
+#endif
   )
 import GHC.Core.Type
   ( eqType, mkTyConTy, mkTyConApp, splitTyConApp_maybe
@@ -496,16 +499,11 @@ #if HAS_REWRITING
   , TcPluginSolveResult(..), TcPluginRewriteResult(..)
   , RewriteEnv(..)
-#else
-  , TcPluginResult(..)
 #endif
   )
 import GHC.Tc.Types.Constraint
   ( Ct(..), CtLoc(..), CtEvidence(..), CtFlavour(..)
   , QCInst(..)
-#if MIN_VERSION_ghc(9,2,0)
-  , CanEqLHS(..)
-#endif
   , ctPred, ctLoc, ctEvidence, ctEvExpr
   , ctFlavour, ctEqRel, ctOrigin
   , bumpCtLocDepth
@@ -530,8 +528,15 @@   )
 import GHC.Types.Unique
   ( Unique )
-import GHC.Types.Unique.FM
+#if MIN_VERSION_ghc(9,0,0)
+import GHC.Types.Unique.FM as UniqFM
   ( UniqFM, emptyUFM, listToUFM )
+#else
+import qualified GHC.Types.Unique.FM as GHC
+  ( UniqFM )
+import GHC.Types.Unique.FM as UniqFM
+  ( emptyUFM, listToUFM )
+#endif
 import GHC.Types.Unique.DFM
   ( UniqDFM, lookupUDFM, lookupUDFM_Directly, elemUDFM )
 import GHC.Types.Var
@@ -801,3 +806,11 @@   -> Reduction
 mkTyFamAppReduction str role tc args ty =
   Reduction ( mkPluginUnivCo str role ( mkTyConApp tc args ) ty ) ty
+
+--------------------------------------------------------------------------------
+
+#if !MIN_VERSION_ghc(9,0,0)
+
+type UniqFM ty a = GHC.UniqFM a
+
+#endif
src/GHC/TcPlugin/API/Internal.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE GADTs #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE QuantifiedConstraints #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -59,6 +60,8 @@   where
 
 -- base
+import Data.Coerce
+  ( Coercible )
 import Data.Kind
   ( Constraint, Type )
 import GHC.TypeLits
@@ -186,10 +189,10 @@ -- > myTcPlugin :: [String] -> GHC.TcPlugin.API.TcPlugin
 -- > myTcPlugin args = ...
 data TcPlugin = forall s. TcPlugin
-  { tcPluginInit    :: TcPluginM Init s
+  { tcPluginInit :: TcPluginM Init s
       -- ^ Initialise plugin, when entering type-checker.
 
-  , tcPluginSolve   :: s -> TcPluginSolver
+  , tcPluginSolve :: s -> TcPluginSolver
       -- ^ Solve some constraints.
       --
       -- This function will be invoked at two points in the constraint solving
@@ -204,7 +207,12 @@       -- Use @ \\ _ _ _ -> pure $ TcPluginOK [] [] @ if your plugin
       -- does not provide this functionality.
 
-  , tcPluginRewrite :: s -> GHC.UniqFM GHC.TyCon TcPluginRewriter
+  , tcPluginRewrite
+      :: s -> GHC.UniqFM
+#if MIN_VERSION_ghc(9,0,0)
+                GHC.TyCon
+#endif
+                TcPluginRewriter
     -- ^ Rewrite saturated type family applications.
     --
     -- The plugin is expected to supply a mapping from type family names to
@@ -216,7 +224,7 @@     --
     -- Use @ const emptyUFM @ if your plugin does not provide this functionality.
 
-  , tcPluginStop    :: s -> TcPluginM Stop ()
+  , tcPluginStop :: s -> TcPluginM Stop ()
    -- ^ Clean up after the plugin, when exiting the type-checker.
   }
 
@@ -286,7 +294,7 @@ -- Note that you must import the internal module in order to access the methods.
 -- Please report a bug if you find yourself needing this functionality.
 type  MonadTcPlugin :: ( Type -> Type ) -> Constraint
-class Monad m => MonadTcPlugin m where
+class ( Monad m, ( forall x y. Coercible x y => Coercible (m x) (m y) ) ) => MonadTcPlugin m where
 
   {-# MINIMAL liftTcPluginM, unsafeWithRunInTcM #-}
 
@@ -361,7 +369,7 @@ instance MonadTcPlugin ( TcPluginM Stop ) where
   liftTcPluginM = TcPluginStopM
   unsafeWithRunInTcM runInTcM
-    = unsafeLiftTcM $ runInTcM 
+    = unsafeLiftTcM $ runInTcM
 #ifdef HAS_REWRITING
       ( GHC.runTcPluginM . tcPluginStopM )
 #else
@@ -432,7 +440,12 @@ #else
     adaptUserSolveAndRewrite
       :: ( userDefs -> TcPluginSolver )
-      -> ( userDefs -> GHC.UniqFM GHC.TyCon TcPluginRewriter )
+      -> ( userDefs -> GHC.UniqFM
+#if MIN_VERSION_ghc(9,0,0)
+                         GHC.TyCon
+#endif
+                         TcPluginRewriter
+         )
       -> TcPluginDefs userDefs
       -> GHC.TcPluginSolver
     adaptUserSolveAndRewrite userSolve userRewrite ( TcPluginDefs { tcPluginUserDefs, tcPluginBuiltinDefs } )
@@ -492,7 +505,7 @@ -- | Use this type like 'GHC.TypeLits.ErrorMessage' to write an error message.
 -- This error message can then be thrown at the type-level by the plugin,
 -- by emitting a wanted constraint whose predicate is obtained from 'mkTcPluginErrorTy'.
--- 
+--
 -- A 'GHC.Tc.Types.Constraint.CtLoc' will still need to be provided in order to inform GHC of the
 -- origin of the error (e.g.: which part of the source code should be
 -- highlighted?). See 'GHC.TcPlugin.API.setCtLocM'.
src/GHC/TcPlugin/API/Internal/Shim.hs view
@@ -18,7 +18,7 @@ 
 module GHC.TcPlugin.API.Internal.Shim
   ( Reduction(..), mkReduction
-  , TcPluginSolveResult, TcPluginRewriteResult(..)
+  , TcPluginSolveResult(TcPluginContradiction, TcPluginOk, ..), TcPluginRewriteResult(..)
   , RewriteEnv(..)
   , shimRewriter
   )
@@ -28,11 +28,13 @@ import Prelude
   hiding ( Floating(cos), iterate )
 import Control.Monad
-  ( forM, when )
-#if !MIN_VERSION_ghc(9,2,0)
+  ( forM, unless, when )
 import Data.Foldable
-  ( foldlM )
+  ( traverse_
+#if !MIN_VERSION_ghc(9,2,0)
+  , foldlM
 #endif
+  )
 #if MIN_VERSION_ghc(9,2,0)
 import Data.List.NonEmpty
   ( NonEmpty((:|)) )
@@ -71,7 +73,11 @@   )
 import GHC.Core.Type
   ( TyVar
-  , tcView , mkTyConApp, mkScaled, coreView , tymult, tyVarKind
+  , tcView , mkTyConApp
+#if MIN_VERSION_ghc(9,0,0)
+  , mkScaled, tymult
+#endif
+  , coreView, tyVarKind
   )
 #if MIN_VERSION_ghc(9,2,0)
 import GHC.Data.Maybe
@@ -88,6 +94,7 @@   , matchFam
   , runTcPluginTcS, runTcSWithEvBinds
   , traceTcS
+  , setWantedEvTerm
 #if MIN_VERSION_ghc(9,2,0)
   , lookupFamAppCache, lookupFamAppInert, extendFamAppCache
   , pattern EqualCtList
@@ -96,11 +103,13 @@ #endif
   )
 import GHC.Tc.Types
-  ( TcPluginM, TcPluginResult(..)
+  ( TcPluginM
   , unsafeTcPluginTcM, getEvBindsTcPluginM
   )
+import qualified GHC.Tc.Types as GHC
+  ( TcPluginResult(..) )
 import GHC.Tc.Types.Constraint
-  ( Ct(..)
+  ( Ct(..), CtEvidence(..)
   , CtLoc, CtFlavour(..), CtFlavourRole, ShadowInfo(..)
 #if MIN_VERSION_ghc(9,2,0)
   , CanEqLHS(..)
@@ -149,14 +158,89 @@ 
 --------------------------------------------------------------------------------
 
+-- | The type-family rewriting environment.
 data RewriteEnv
   = FE { fe_loc     :: !CtLoc
        , fe_flavour :: !CtFlavour
        , fe_eq_rel  :: !EqRel
        }
 
-type TcPluginSolveResult = TcPluginResult
+-- | Result of running a solver plugin.
+data TcPluginSolveResult
+  = TcPluginSolveResult
+  { -- | Insoluble constraints found by the plugin.
+    --
+    -- These constraints will be added to the inert set,
+    -- and reported as insoluble to the user.
+    tcPluginInsolubleCts :: [Ct]
+    -- | Solved constraints, together with their evidence.
+    --
+    -- These are removed from the inert set, and the
+    -- evidence for them is recorded.
+  , tcPluginSolvedCts :: [(EvTerm, Ct)]
+    -- | New constraints that the plugin wishes to emit.
+    --
+    -- These will be added to the work list.
+  , tcPluginNewCts :: [Ct]
+  }
 
+-- | The plugin found a contradiction.
+-- The returned constraints are removed from the inert set,
+-- and recorded as insoluble.
+--
+-- The returned list of constraints should never be empty.
+pattern TcPluginContradiction :: [Ct] -> TcPluginSolveResult
+pattern TcPluginContradiction insols
+  = TcPluginSolveResult
+  { tcPluginInsolubleCts = insols
+  , tcPluginSolvedCts    = []
+  , tcPluginNewCts       = [] }
+
+-- | The plugin has not found any contradictions,
+--
+-- The first field is for constraints that were solved.
+-- The second field contains new work, that should be processed by
+-- the constraint solver.
+pattern TcPluginOk :: [(EvTerm, Ct)] -> [Ct] -> TcPluginSolveResult
+pattern TcPluginOk solved new
+  = TcPluginSolveResult
+  { tcPluginInsolubleCts = []
+  , tcPluginSolvedCts    = solved
+  , tcPluginNewCts       = new }
+
+-- The 'TcPluginSolveResult' datatype changed in GHC 9.4,
+-- allowing users to return solved and new constraints even in case of
+-- a contradiction.
+--
+-- This function simply drops the solved and new constraints on older versions,
+-- although it does at least still bind the evidence in case of solved Wanteds.
+adaptSolveResult :: Bool -> TcPluginSolveResult -> TcPluginM GHC.TcPluginResult
+adaptSolveResult doingGivens
+  ( TcPluginSolveResult
+    { tcPluginInsolubleCts = insols
+    , tcPluginSolvedCts    = solved
+    , tcPluginNewCts       = new
+    }
+  )
+    | null insols
+    = pure $ GHC.TcPluginOk solved new
+    | null solved && null new
+    = pure $ GHC.TcPluginContradiction insols
+    | otherwise
+    = do
+      evBinds <- getEvBindsTcPluginM
+      unsafeTcPluginTcM . runTcSWithEvBinds evBinds $ do
+        unless doingGivens $ traverse_ ( uncurry setEv ) solved
+        --updInertCans (removeInertCts $ fmap snd solved) -- These don't do anything, as the inert set and work list
+        --emitWork new                                    -- are confined to this run of the plugin.
+      pure $ GHC.TcPluginContradiction insols
+  where
+    setEv :: EvTerm -> Ct -> TcS ()
+    setEv ev ( ctEvidence -> CtWanted { ctev_dest = dest } )
+      = setWantedEvTerm dest ev
+    setEv _ _
+      = pure ()
+
 data TcPluginRewriteResult
   =
   -- | The plugin does not rewrite the type family application.
@@ -173,28 +257,38 @@ 
 type Rewriter = RewriteEnv -> [Ct] -> [Type] -> TcPluginM TcPluginRewriteResult
 
-type Rewriters = UniqFM TyCon Rewriter
+type Rewriters =
+  UniqFM
+#if MIN_VERSION_ghc(9,0,0)
+    TyCon
+#endif
+    Rewriter
 
+-- | Emulate type-family rewriting functionality in a constraint solving plugin,
+-- by traversing through all the constraints and rewriting any type-family applications
+-- inside them.
 shimRewriter :: [Ct] -> [Ct] -> [Ct]
              -> Rewriters
              -> ( [Ct] -> [Ct] -> [Ct] -> TcPluginM TcPluginSolveResult )
-             -> TcPluginM TcPluginSolveResult
+             -> TcPluginM GHC.TcPluginResult
 shimRewriter givens deriveds wanteds rws solver
   | isNullUFM rws
-  = solver givens deriveds wanteds
+  = adaptSolveResult (null wanteds) =<< solver givens deriveds wanteds
   | otherwise
   = do
-    res <- solver givens deriveds wanteds
-    case res of
-      contra@( TcPluginContradiction {} ) ->
-        pure contra
-      TcPluginOk solved new -> do
-        ( rewrittenDeriveds, solvedDeriveds, newCts1 ) <- traverseCts ( reduceCt rws givens ) deriveds
-        ( rewrittenWanteds , solvedWanteds , newCts2 ) <- traverseCts ( reduceCt rws givens ) wanteds
-        pure $
-            TcPluginOk
-              ( solved ++ solvedDeriveds ++ solvedWanteds )
-              ( new ++ newCts1 ++ rewrittenDeriveds ++ newCts2 ++ rewrittenWanteds )
+    TcPluginSolveResult
+      { tcPluginInsolubleCts = contras
+      , tcPluginSolvedCts    = solved
+      , tcPluginNewCts       = new
+      } <- solver givens deriveds wanteds
+    ( rewrittenDeriveds, solvedDeriveds, newCts1 ) <- traverseCts ( reduceCt rws givens ) deriveds
+    ( rewrittenWanteds , solvedWanteds , newCts2 ) <- traverseCts ( reduceCt rws givens ) wanteds
+    adaptSolveResult (null wanteds) $
+      TcPluginSolveResult
+        { tcPluginInsolubleCts = contras
+        , tcPluginSolvedCts    = solved ++ solvedDeriveds ++ solvedWanteds
+        , tcPluginNewCts       = new ++ newCts1 ++ rewrittenDeriveds ++ newCts2 ++ rewrittenWanteds
+        }
 
 reduceCt :: Rewriters
          -> [Ct]
@@ -262,12 +356,31 @@   | otherwise
   = rewrite_ty_con_app tc tys
 
-rewrite_one (FunTy { ft_af = vis, ft_mult = mult, ft_arg = ty1, ft_res = ty2 })
+rewrite_one
+  (FunTy
+    { ft_af = vis
+#if MIN_VERSION_ghc(9,0,0)
+    , ft_mult = mult
+#endif
+    , ft_arg = ty1
+    , ft_res = ty2
+    })
   = do { arg_redn <- rewrite_one ty1
        ; res_redn <- rewrite_one ty2
+#if MIN_VERSION_ghc(9,0,0)
        ; w_redn <- setEqRel NomEq $ rewrite_one mult
+#endif
        ; role <- getRole
-       ; return $ mkFunRedn role vis w_redn arg_redn res_redn }
+       ; return $
+           mkFunRedn
+             role
+             vis
+#if MIN_VERSION_ghc(9,0,0)
+             w_redn
+#endif
+             arg_redn
+             res_redn
+        }
 
 rewrite_one ty@(ForAllTy {})
   = do { let (bndrs, rho) = tcSplitForAllTyVarBinders ty
@@ -555,9 +668,27 @@   split _ (ForAllTy b res) =
     let !(bs, ty', _) = split res res
     in  (Named b : bs, ty', True)
-  split _ (FunTy { ft_af = af, ft_mult = w, ft_arg = arg, ft_res = res }) =
+  split _
+    (FunTy
+      { ft_af = af
+#if MIN_VERSION_ghc(9,0,0)
+      , ft_mult = w
+#endif
+      , ft_arg = arg
+      , ft_res = res
+      }
+    ) =
     let !(bs, ty', named) = split res res
-    in  (Anon af (mkScaled w arg) : bs, ty', named)
+    in  ( Anon
+          af
+#if MIN_VERSION_ghc(9,0,0)
+          (mkScaled w arg)
+#else
+          arg
+#endif
+          : bs
+        , ty', named
+        )
   split orig_ty ty' | Just ty'' <- coreView ty' = split orig_ty ty''
   split orig_ty _ = ([], orig_ty, False)
 {-# INLINE split_pi_tys' #-}
@@ -568,7 +699,15 @@     go (Bndr tv (NamedTCB vis)) (bndrs, _)
       = (Named (Bndr tv vis) : bndrs, True)
     go (Bndr tv (AnonTCB af))   (bndrs, n)
-      = (Anon af (tymult (tyVarKind tv)) : bndrs, n)
+      = (Anon af
+          (
+#if MIN_VERSION_ghc(9,0,0)
+            tymult
+#endif
+             (tyVarKind tv)
+          )
+          : bndrs
+        , n)
     {-# INLINE go #-}
 {-# INLINE ty_con_binders_ty_binders' #-}
 
src/GHC/TcPlugin/API/Internal/Shim/Reduction.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
 
 module GHC.TcPlugin.API.Internal.Shim.Reduction where
 
@@ -12,8 +13,13 @@ import GHC.Core.Coercion
   ( Coercion, CoercionN, MCoercion(..)
   , Role(Nominal), LiftingContext
+#if MIN_VERSION_ghc(9,0,0)
   , castCoercionKind1, castCoercionKind2
-  , coercionLKind, coercionRKind, coercionKind
+  , coercionLKind, coercionRKind
+#else
+  , mkCoherenceLeftCo, mkNomReflCo
+#endif
+  , coercionKind
   , coToMCo
   , decomposePiCos, downgradeRole
   , liftCoSubst, emptyLiftingContext, extendLiftingContextAndInScope, zapLiftingContext
@@ -27,7 +33,11 @@ import GHC.Core.Predicate
   ( mkClassPred )
 import GHC.Core.TyCo.Rep
-  ( TyCoBinder, mkFunTy )
+  ( TyCoBinder, mkFunTy
+#if !MIN_VERSION_ghc(9,0,0)
+  , Coercion(..)
+#endif
+  )
 import GHC.Core.TyCon
   ( TyCon )
 import GHC.Core.Type
@@ -314,17 +324,35 @@ -- Combines 'mkFunCo' and 'mkFunTy'.
 mkFunRedn :: Role
           -> AnonArgFlag
+#if MIN_VERSION_ghc(9,0,0)
           -> ReductionN -- ^ multiplicity reduction
+#endif
           -> Reduction  -- ^ argument reduction
           -> Reduction  -- ^ result reduction
           -> Reduction
 mkFunRedn r vis
+#if MIN_VERSION_ghc(9,0,0)
   (Reduction w_co w_ty)
+#endif
   (Reduction arg_co arg_ty)
   (Reduction res_co res_ty)
     = mkReduction
-        (mkFunCo r w_co arg_co res_co)
-        (mkFunTy vis w_ty arg_ty res_ty)
+        ( mkFunCo
+            r
+#if MIN_VERSION_ghc(9,0,0)
+            w_co
+#endif
+            arg_co
+            res_co
+        )
+        ( mkFunTy
+            vis
+#if MIN_VERSION_ghc(9,0,0)
+            w_ty
+#endif
+            arg_ty
+            res_ty
+        )
 {-# INLINE mkFunRedn #-}
 
 -- | Create a 'Reduction' associated to a Π type,
@@ -516,3 +544,39 @@ mkTransMCoR :: Coercion -> MCoercion -> MCoercion
 mkTransMCoR co1 MRefl     = coToMCo co1
 mkTransMCoR co1 (MCo co2) = MCo (mkTransCo co1 co2)
+
+--------------------------------------------------------------------------------
+
+#if !MIN_VERSION_ghc(9,0,0)
+
+coercionLKind, coercionRKind :: Coercion -> Type
+coercionLKind co = case coercionKind co of { Pair lco _ -> lco }
+coercionRKind co = case coercionKind co of { Pair _ rco -> rco }
+
+-- | Creates a new coercion with both of its types casted by different casts
+-- @castCoercionKind2 g r t1 t2 h1 h2@, where @g :: t1 ~r t2@,
+-- has type @(t1 |> h1) ~r (t2 |> h2)@.
+-- @h1@ and @h2@ must be nominal.
+castCoercionKind2 :: Coercion -> Role -> Type -> Type
+                 -> CoercionN -> CoercionN -> Coercion
+castCoercionKind2 g r t1 t2 h1 h2
+  = mkCoherenceRightCo r t2 h2 (mkCoherenceLeftCo r t1 h1 g)
+
+-- | @castCoercionKind1 g r t1 t2 h@ = @coercionKind g r t1 t2 h h@
+-- That is, it's a specialised form of castCoercionKind, where the two
+--          kind coercions are identical
+-- @castCoercionKind1 g r t1 t2 h@, where @g :: t1 ~r t2@,
+-- has type @(t1 |> h) ~r (t2 |> h)@.
+-- @h@ must be nominal.
+-- See Note [castCoercionKind1]
+castCoercionKind1 :: Coercion -> Role -> Type -> Type
+                  -> CoercionN -> Coercion
+castCoercionKind1 g r t1 t2 h
+  = case g of
+      Refl {} -> mkNomReflCo (mkCastTy t2 h)
+      GRefl _ _ mco -> case mco of
+           MRefl       -> mkReflCo r (mkCastTy t2 h)
+           MCo kind_co -> GRefl r (mkCastTy t1 h) $
+                          MCo (mkSymCo h `mkTransCo` kind_co `mkTransCo` h)
+      _ -> castCoercionKind2 g r t1 t2 h h
+#endif
+ src/GHC/TcPlugin/API/Names.hs view
@@ -0,0 +1,465 @@+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralisedNewtypeDeriving #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE QuantifiedConstraints #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneKindSignatures #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+{-|
+Module: GHC.TcPlugin.API.Names
+
+This module provides an /optional/ framework that facilitates name lookup
+in type-checking plugins, using constrained traversals (similar to the
+<https://hackage.haskell.org/package/barbies barbies library>).
+
+See the 'ResolveNames' typeclass.
+
+Before:
+
+> data PluginDefs =
+>   PluginDefs
+>     { myTyCon           :: TyCon
+>     , myClass           :: Class
+>     , myPromotedDataCon :: TyCon
+>     }
+>
+> findMyModule :: MonadTcPlugin m => m Module
+> findMyModule = do
+>   findResult <- findImportedModule ( mkModuleName "MyModule" ) Nothing
+>   case findResult of
+>     Found _ res -> pure res
+>     _           -> error $ "MyPlugin: could not find any module named MyModule."
+>
+> pluginInit :: TcPluginM Init PluginDefs
+> pluginInit = do
+>   myModule <- findMyModule
+>   myTyCon           <-                       tcLookupTyCon   =<< lookupOrig myModule ( mkTcOcc   "MyTyCon"   )
+>   myClass           <-                       tcLookupClass   =<< lookupOrig myModule ( mkClsOcc  "MyClass"   )
+>   myPromotedDataCon <- fmap promoteDataCon . tcLookupDataCon =<< lookupOrig myModule ( mkDataOcc "MyDataCon" )
+>   pure ( PluginDefs { .. } )
+
+After:
+
+> data PluginDefsHKD n =
+>   PluginDefs
+>     { myTyCon            :: Wear n TyCon
+>     , myClass            :: Wear n Class
+>     , myPromotedDataCon  :: Wear n ( Promoted DataCon )
+>     }
+>   deriving stock Generic
+>   deriving ResolveNames
+>     via Generically1 PluginDefsHKD
+>
+> type PluginDefs = PluginDefsHKD Resolved
+>
+> pluginInit :: TcPluginM Init PluginDefs
+> pluginInit = resolveNames pluginNames
+>   where
+>     pluginNames :: PluginDefsHKD Named
+>     pluginNames =
+>       PluginDefs
+>         { myTyCon           = mkQualified "MyTyCon"
+>         , myClass           = mkQualified "MyClass"
+>         , myPromotedDataCon = mkQualified "MyDataCon"
+>         }
+>     mkQualified :: String -> QualifiedName thing
+>     mkQualified str =
+>       Qualified
+>         { name    = str
+>         , module' = mkModuleName "MyModule"
+>         , package = Nothing
+>         }
+
+-}
+
+module GHC.TcPlugin.API.Names
+  ( ResolveNames, resolveNames
+  , Wear, QualifiedName(..), NameResolution(..)
+  , Promoted
+  , Lookupable(..)
+
+    -- * Re-export Generically1 for compatibility.
+  , Generically1(..)
+  ) where
+
+-- base
+import Prelude
+  hiding ( lookup )
+import Data.Coerce
+  ( Coercible, coerce )
+import Data.Kind
+  ( Type, Constraint )
+import GHC.Generics
+  ( Generic(..)
+#if MIN_VERSION_base(4,17,0)
+  , Generically1(..)
+#endif
+  , (:+:)(..), (:*:)(..)
+  , K1(K1), M1(M1), U1(..), V1, Rec0
+  )
+import GHC.TypeLits
+  ( TypeError, ErrorMessage(..) )
+
+-- transformers
+import Control.Monad.Trans.State.Strict
+  ( StateT, evalStateT, get, put )
+import Control.Monad.Trans.Class
+  ( MonadTrans(lift) )
+
+-- ghc
+#if MIN_VERSION_ghc(9,3,0)
+import GHC.Iface.Errors
+  ( cannotFindModule )
+#elif MIN_VERSION_ghc(9,2,0)
+import GHC.Iface.Load
+  ( cannotFindModule )
+#else
+import GHC.Driver.Types
+  ( hsc_dflags )
+import GHC.Driver.Finder
+  ( cannotFindModule )
+import GHC.Driver.Session
+  ( DynFlags )
+#endif
+import GHC.Utils.Panic
+  ( pgmErrorDoc )
+import GHC.Unit.Module.Name
+  ( moduleNameString )
+import GHC.Tc.Plugin
+  ( getTopEnv )
+import GHC.Types.Unique.FM
+  ( addToUFM, addToUFM_C, lookupUFM, plusUFM, unitUFM )
+
+-- ghc-tcplugin-api
+import GHC.TcPlugin.API
+  hiding ( Type )
+import GHC.TcPlugin.API.Internal
+  ( MonadTcPlugin(liftTcPluginM) )
+
+--------------------------------------------------------------------------------
+
+-- | A 'QualifiedName' is the name of something,
+-- together with the names of the module and package it comes from.
+type QualifiedName :: k -> Type
+data QualifiedName thing
+  = Qualified
+    { -- | Name of the thing (e.g. name of the 'TyCon' or 'Class').
+      name    :: String
+      -- | Name of the module in which the thing can be found.
+    , module' :: ModuleName
+      -- | Name of the package in which the module can be found.
+      -- Use 'Nothing' to signify the current home package.
+    , package :: Maybe FastString
+    }
+
+-- | Type-level parameter to 'Wear' type family, for higher-kinded data.
+--
+-- @Wear Named thing@ is the identifier data passed in as an argument.
+-- @Wear Resolved thing@ is the result of name resolving the thing.
+--
+-- This allows users to pass a record of names, of type @MyData Named@,
+-- and obtain a record of looked-up things, of type @MyData Resolved@.
+--
+-- Refer to 'ResolveNames' for a worked example.
+data NameResolution = Named | Resolved
+
+-- | Use this to refer to a @Promoted DataCon@.
+type Promoted :: k -> Type
+data Promoted thing
+
+-- | Type-family used for higher-kinded data pattern.
+--
+-- This allows the same record to be re-used,
+-- as explained in the worked example for 'ResolveNames'.
+--
+-- For instance, if one defines:
+--
+-- > data MyData n
+-- >   = MyData
+-- >   { myClass :: !( Wear n Class )
+-- >   , myTyCon :: !( Wear n TyCon )
+-- >   }
+--
+-- then a record of type @MyData Named@ is simply a record of textual names
+-- (a typeclass name and a type-constructor name, with associated module & packages),
+-- whereas a record of type @MyData Resolved@ contains a typeclass's @Class@
+-- as well as a type-constructor's @TyCon@.
+type Wear :: forall k. NameResolution -> k -> Type
+type family Wear n thing where
+  Wear Named    thing              = QualifiedName thing
+  Wear Resolved (Promoted DataCon) = TyCon
+  Wear Resolved (Promoted a)
+    = TypeError
+      ( Text "Cannot promote " :<>: ShowType a :<>: Text "."
+      :$$: Text "Can only promote 'DataCon's."
+      )
+  Wear Resolved thing = thing
+
+-- | Retrieve the underlying thing being referred to by inspecting
+-- the type parameter of 'QualifiedName'.
+type UnwearNamed :: Type -> Type
+type family UnwearNamed loc where
+  UnwearNamed (QualifiedName thing) = thing
+
+-- | Type-class overloading things that can be looked up by name:
+--
+-- * classes,
+-- * data constructors (as well as their promotion),
+-- * type-constructors.
+#if MIN_VERSION_ghc(9,0,0)
+type Lookupable :: forall {k}. k -> Constraint
+#endif
+class Lookupable a where
+  mkOccName :: String -> OccName
+  lookup :: MonadTcPlugin m => Name -> m (Wear Resolved a)
+
+instance Lookupable TyCon where
+  mkOccName = mkTcOcc
+  lookup = tcLookupTyCon
+instance Lookupable DataCon where
+  mkOccName = mkDataOcc
+  lookup = tcLookupDataCon
+instance Lookupable Class where
+  mkOccName = mkClsOcc
+  lookup = tcLookupClass
+instance Lookupable (Promoted DataCon) where
+  mkOccName = mkDataOcc
+  lookup = fmap promoteDataCon . tcLookupDataCon
+
+-- | This class exposes the method 'resolveNames' which will
+-- perform name resolution for all the fields in a datatype.
+--
+-- Example usage: we define a record that will hold
+-- the things we want to look up, using the 'Wear' type family.
+--
+-- For example:
+--
+--  > data MyData n
+--  >   = MyData
+--  >   { myClass       :: !( Wear n Class )
+--  >   , myTyCon       :: !( Wear n TyCon )
+--  >   , myDataCon     :: !( Wear n DataCon )
+--  >   , myPromDataCon :: !( Wear n (Promoted DataCon) )
+--  >   }
+--  >   deriving stock Generic
+--  >   deriving ResolveNames
+--  >     via Generically1 MyData
+--
+-- Now we can specify the names of the things which we want to look up,
+-- together with the modules and packages in which they belong:
+--
+-- > myNames :: MyData Named
+-- > myNames = MyData
+-- >  { myClass = QualifiedName "MyClass" "My.Module" ( Just "my-pkg-name" )
+-- >  , ...
+-- >  }
+--
+-- Then we can call 'resolveNames':
+--
+-- > resolvedNames :: MonadTcPlugin m => m (MyData Resolved)
+-- > resolvedNames = resolveNames myNames
+--
+-- This returns a record containing the looked up things we want,
+-- e.g. @myClass :: Class@, @myPromDataCon :: TyCon@, etc.
+type ResolveNames :: ( NameResolution -> Type ) -> Constraint
+class ResolveNames f where
+  resolve_names :: ( Coercible res ( f Resolved ), MonadTcPlugin m )
+                => f Named -> m res
+  -- Workaround: the result is anything coercible to "f Resolved" rather than just "f Resolved",
+  -- because otherwise GHC complains when using DerivingVia that we don't know the role
+  -- of the parameter to m, despite the quantified constraint superclass to MonadTcPlugin.
+  --
+  -- This unfortunately worsens type-inference, so we export
+  -- 'resolveNames' separately.
+
+-- | Resolve a collection of names.
+--
+-- See 'ResolveNames' for further details.
+resolveNames :: ( MonadTcPlugin m, ResolveNames f )
+             => f Named -> m ( f Resolved )
+resolveNames = resolve_names
+
+instance ( Generic (f Named)
+         , Generic (f Resolved)
+         , GTraversableC ResolveName (Rep (f Named)) (Rep (f Resolved))
+         )
+      => ResolveNames (Generically1 f) where
+  resolve_names
+    :: forall
+#if MIN_VERSION_ghc(9,0,0)
+         {m}
+#else
+          m
+#endif
+         res
+    .  ( Coercible res ( Generically1 f Resolved ), MonadTcPlugin m )
+    => Generically1 f Named -> m res
+  resolve_names dat
+    =  ( `evalStateT` emptyModules )
+    $  coerce . to @(f Resolved)
+   <$> gtraverseC @ResolveName resolveName ( from dat )
+
+-- | Type-class dispatch for looking up names.
+--
+-- Every instance is of the form:
+--
+-- > ResolveName (Wear Named thing) (Wear Resolved thing)
+--
+-- which allows one to write 'resolveName':
+--
+-- > resolveName :: ... => Wear Named thing -> m ( Wear Resolved thing )
+type     ResolveName :: Type -> Type -> Constraint
+class    ( a ~ Wear Named    ( UnwearNamed a )
+         , b ~ Wear Resolved ( UnwearNamed a )
+         , Lookupable ( UnwearNamed a )
+         )
+      => ResolveName a b
+instance ( a ~ Wear Named    ( UnwearNamed a )
+         , b ~ Wear Resolved ( UnwearNamed a )
+         , Lookupable ( UnwearNamed a )
+         )
+      => ResolveName a b
+
+resolveName :: forall thing m
+            .  ResolveName ( Wear Named thing ) ( Wear Resolved thing )
+            => MonadTcPlugin m
+            => Wear Named thing
+            -> StateT ImportedModules m ( Wear Resolved thing )
+resolveName (Qualified str mod_name mb_pkg) = do
+  md <- lookupModule mb_pkg mod_name
+  nm <- lift $ lookupOrig md (mkOccName @thing str)
+  lift $ lookup @thing nm
+
+--------------------------------------------------------------------------------
+-- Caching of found modules.
+
+data ImportedModules
+  = ImportedModules
+    { home_modules :: UniqFM ModuleName Module
+    , pkg_modules  :: UniqFM FastString ( UniqFM ModuleName Module )
+    }
+
+emptyModules :: ImportedModules
+emptyModules = ImportedModules emptyUFM emptyUFM
+
+lookupCachedModule :: Monad m => Maybe FastString -> ModuleName -> StateT ImportedModules m (Maybe Module)
+lookupCachedModule Nothing    mod_name
+  =   ( `lookupUFM` mod_name )
+  .   home_modules
+  <$> get
+lookupCachedModule (Just pkg) mod_name
+  =   ( ( `lookupUFM` mod_name ) =<< )
+  .   ( `lookupUFM` pkg )
+  .   pkg_modules
+  <$> get
+
+insertCachedModule :: Monad m => Maybe FastString -> ModuleName -> Module -> StateT ImportedModules m ()
+insertCachedModule Nothing    mod_name md = do
+  mods@( ImportedModules { home_modules = prev } ) <- get
+  put $ mods { home_modules = addToUFM prev mod_name md }
+insertCachedModule (Just pkg) mod_name md = do
+  mods@( ImportedModules { pkg_modules = prev } ) <- get
+  put $ mods { pkg_modules = addToUFM_C plusUFM prev pkg (unitUFM mod_name md) }
+
+lookupModule :: MonadTcPlugin m => Maybe FastString -> ModuleName -> StateT ImportedModules m Module
+lookupModule mb_pkg mod_name = do
+  cachedResult <- lookupCachedModule mb_pkg mod_name
+  case cachedResult of
+    Just res -> do
+      insertCachedModule mb_pkg mod_name res
+      pure res
+    Nothing -> do
+      findResult <- lift $ findImportedModule mod_name mb_pkg
+      case findResult of
+        Found _ res
+          -> pure res
+        other -> do
+          hsc_env <- lift . liftTcPluginM $ getTopEnv
+          let
+            err_doc :: SDoc
+#if MIN_VERSION_ghc(9,2,0)
+            err_doc = cannotFindModule hsc_env mod_name other
+#else
+            err_doc = cannotFindModule dflags  mod_name other
+            dflags :: DynFlags
+            dflags = hsc_dflags hsc_env
+#endif
+          pgmErrorDoc
+            ( "GHC.TcPlugin.API: could not find module " <> mod_str <> " in " <> pkg_name )
+            err_doc
+  where
+    pkg_name, mod_str :: String
+    pkg_name = case mb_pkg of
+      Just pkg -> "package " <> show pkg
+      Nothing  -> "home package"
+    mod_str = moduleNameString mod_name
+
+--------------------------------------------------------------------------------
+-- Constrained traversals.
+
+type TraversalC :: ( Type -> Type -> Constraint ) -> Type -> Type -> Type
+type TraversalC c s t
+  =  forall f. ( Applicative f )
+  => ( forall a b. c a b => a -> f b ) -> s -> f t
+
+type GTraversableC :: ( Type -> Type -> Constraint )
+                   -> ( Type -> Type )
+                   -> ( Type -> Type )
+                   -> Constraint
+class GTraversableC c s t where
+  gtraverseC :: TraversalC c (s x) (t x)
+
+instance
+  ( GTraversableC c l l'
+  , GTraversableC c r r'
+  ) => GTraversableC c (l :*: r) (l' :*: r') where
+  gtraverseC f (l :*: r)
+    = (:*:) <$> gtraverseC @c f l <*> gtraverseC @c f r
+
+instance
+  ( GTraversableC c l l'
+  , GTraversableC c r r'
+  ) => GTraversableC c (l :+: r) (l' :+: r') where
+  gtraverseC f (L1 l) = L1 <$> gtraverseC @c f l
+  gtraverseC f (R1 r) = R1 <$> gtraverseC @c f r
+
+instance GTraversableC c s t
+  => GTraversableC c (M1 i m s) (M1 i m t) where
+  gtraverseC f (M1 x) = M1 <$> gtraverseC @c f x
+
+instance GTraversableC c U1 U1 where
+  gtraverseC _ _ = pure U1
+
+instance GTraversableC c V1 V1 where
+  gtraverseC _ = pure
+
+instance c a b => GTraversableC c (Rec0 a) (Rec0 b) where
+  gtraverseC f (K1 a) = K1 <$> f a
+
+--------------------------------------------------------------------------------
+-- Generically and Generically1 wrappers for DerivingVia.
+
+#if !MIN_VERSION_base(4,17,0)
+-- | A type whose instances are defined generically, using the
+-- 'Generic1' representation. 'Generically1' is a higher-kinded
+-- version of 'Generically' that uses 'Generic'.
+--
+-- Generic instances can be derived for type constructors via
+-- @'Generically1' F@ using @-XDerivingVia@.
+type    Generically1 :: ( k -> Type ) -> ( k -> Type )
+newtype Generically1 f a = Generically1 ( f a )
+  deriving newtype Generic
+#endif