    {-# LANGUAGE DeriveFunctor       #-}
    {-# LANGUAGE FlexibleContexts    #-}
    {-# LANGUAGE RankNTypes          #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    {-
    (c) The University of Glasgow 2006
    -}

    -- | Module for (a) type kinds and (b) type coercions,
    -- as used in System FC. See 'GHC.Core.Expr' for
    -- more on System FC and how coercions fit into it.
    --
    module GHC.Core.Coercion (
            -- * Main data type
            Coercion, CoercionN, CoercionR, CoercionP,
            MCoercion(..), MCoercionN, MCoercionR,
            CoSel(..), FunSel(..),
            UnivCoProvenance, CoercionHole(..),
            coHoleCoVar, setCoHoleCoVar,
            LeftOrRight(..),
            Var, CoVar, TyCoVar,
            Role(..), ltRole,

            -- ** Functions over coercions
            coVarRType, coVarLType, coVarTypes,
            coVarKind, coVarKindsTypesRole, coVarRole,
            coercionType, mkCoercionType,
            coercionKind, coercionLKind, coercionRKind,coercionKinds,
            coercionRole, coercionKindRole,

            -- ** Constructing coercions
            mkGReflCo, mkReflCo, mkRepReflCo, mkNomReflCo,
            mkCoVarCo, mkCoVarCos,
            mkAxInstCo, mkUnbranchedAxInstCo,
            mkAxInstRHS, mkUnbranchedAxInstRHS,
            mkAxInstLHS, mkUnbranchedAxInstLHS,
            mkPiCo, mkPiCos, mkCoCast,
            mkSymCo, mkTransCo,
            mkSelCo, getNthFun, getNthFromType, mkLRCo,
            mkInstCo, mkAppCo, mkAppCos, mkTyConAppCo,
            mkFunCo1, mkFunCo2, mkFunCoNoFTF, mkFunResCo,
            mkNakedFunCo1, mkNakedFunCo2,
            mkForAllCo, mkForAllCos, mkHomoForAllCos,
            mkPhantomCo,
            mkHoleCo, mkUnivCo, mkSubCo,
            mkAxiomInstCo, mkProofIrrelCo,
            downgradeRole, mkAxiomRuleCo,
            mkGReflRightCo, mkGReflLeftCo, mkCoherenceLeftCo, mkCoherenceRightCo,
            mkKindCo,
            castCoercionKind, castCoercionKind1, castCoercionKind2,

            mkPrimEqPred, mkReprPrimEqPred, mkPrimEqPredRole,
            mkHeteroPrimEqPred, mkHeteroReprPrimEqPred,

            -- ** Decomposition
            instNewTyCon_maybe,

            NormaliseStepper, NormaliseStepResult(..), composeSteppers, unwrapNewTypeStepper,
            topNormaliseNewType_maybe, topNormaliseTypeX,

            decomposeCo, decomposeFunCo, decomposePiCos, getCoVar_maybe,
            splitAppCo_maybe,
            splitFunCo_maybe,
            splitForAllCo_maybe,
            splitForAllCo_ty_maybe, splitForAllCo_co_maybe,

            tyConRole, tyConRolesX, tyConRolesRepresentational, setNominalRole_maybe,
            tyConRoleListX, tyConRoleListRepresentational, funRole,
            pickLR,

            isGReflCo, isReflCo, isReflCo_maybe, isGReflCo_maybe, isReflexiveCo, isReflexiveCo_maybe,
            isReflCoVar_maybe, isGReflMCo, mkGReflLeftMCo, mkGReflRightMCo,
            mkCoherenceRightMCo,

            coToMCo, mkTransMCo, mkTransMCoL, mkTransMCoR, mkCastTyMCo, mkSymMCo,
            mkHomoForAllMCo, mkFunResMCo, mkPiMCos,
            isReflMCo, checkReflexiveMCo,

            -- ** Coercion variables
            mkCoVar, isCoVar, coVarName, setCoVarName, setCoVarUnique,

            -- ** Free variables
            tyCoVarsOfCo, tyCoVarsOfCos, coVarsOfCo,
            tyCoFVsOfCo, tyCoFVsOfCos, tyCoVarsOfCoDSet,
            coercionSize, anyFreeVarsOfCo,

            -- ** Substitution
            CvSubstEnv, emptyCvSubstEnv,
            lookupCoVar,
            substCo, substCos, substCoVar, substCoVars, substCoWith,
            substCoVarBndr,
            extendTvSubstAndInScope, getCvSubstEnv,

            -- ** Lifting
            liftCoSubst, liftCoSubstTyVar, liftCoSubstWith, liftCoSubstWithEx,
            emptyLiftingContext, extendLiftingContext, extendLiftingContextAndInScope,
            liftCoSubstVarBndrUsing, isMappedByLC,

            mkSubstLiftingContext, zapLiftingContext,
            substForAllCoBndrUsingLC, lcSubst, lcInScopeSet,

            LiftCoEnv, LiftingContext(..), liftEnvSubstLeft, liftEnvSubstRight,
            substRightCo, substLeftCo, swapLiftCoEnv, lcSubstLeft, lcSubstRight,

            -- ** Comparison
            eqCoercion, eqCoercionX,

            -- ** Forcing evaluation of coercions
            seqCo,

            -- * Pretty-printing
            pprCo, pprParendCo,
            pprCoAxiom, pprCoAxBranch, pprCoAxBranchLHS,
            pprCoAxBranchUser, tidyCoAxBndrsForUser,
            etaExpandCoAxBranch,

            -- * Tidying
            tidyCo, tidyCos,

            -- * Other
            promoteCoercion, buildCoercion,

            multToCo, mkRuntimeRepCo,

            hasCoercionHoleTy, hasCoercionHoleCo, hasThisCoercionHoleTy,

            setCoHoleType
           ) where

    import {-# SOURCE #-} GHC.CoreToIface (toIfaceTyCon, tidyToIfaceTcArgs)

    import GHC.Prelude

    import GHC.Iface.Type
    import GHC.Core.TyCo.Rep
    import GHC.Core.TyCo.FVs
    import GHC.Core.TyCo.Ppr
    import GHC.Core.TyCo.Subst
    import GHC.Core.TyCo.Tidy
    import GHC.Core.TyCo.Compare( eqType, eqTypeX )
    import GHC.Core.Type
    import GHC.Core.TyCon
    import GHC.Core.TyCon.RecWalk
    import GHC.Core.Coercion.Axiom
    import GHC.Types.Var
    import GHC.Types.Var.Env
    import GHC.Types.Var.Set
    import GHC.Types.Name hiding ( varName )
    import GHC.Types.Basic
    import GHC.Types.Unique
    import GHC.Data.FastString
    import GHC.Data.Pair
    import GHC.Types.SrcLoc
    import GHC.Builtin.Names
    import GHC.Builtin.Types.Prim
    import GHC.Data.List.SetOps
    import GHC.Data.Maybe
    import GHC.Types.Unique.FM
    import GHC.Data.List.Infinite (Infinite (..))
    import qualified GHC.Data.List.Infinite as Inf

    import GHC.Utils.Misc
    import GHC.Utils.Outputable
    import GHC.Utils.Panic
    import GHC.Utils.Panic.Plain

    import Control.Monad (foldM, zipWithM)
    import Data.Function ( on )
    import Data.Char( isDigit )
    import qualified Data.Monoid as Monoid

    {-
    %************************************************************************
    %*                                                                      *
         -- The coercion arguments always *precisely* saturate
         -- arity of (that branch of) the CoAxiom.  If there are
         -- any left over, we use AppCo.  See
         -- See [Coercion axioms applied to coercions] in GHC.Core.TyCo.Rep

    \subsection{Coercion variables}
    %*                                                                      *
    %************************************************************************
    -}

    coVarName :: CoVar -> Name
    coVarName :: CoVar -> Name
    coVarName = CoVar -> Name
    varName

    setCoVarUnique :: CoVar -> Unique -> CoVar
    setCoVarUnique :: CoVar -> Unique -> CoVar
    setCoVarUnique = CoVar -> Unique -> CoVar
    setVarUnique

    setCoVarName :: CoVar -> Name -> CoVar
    setCoVarName :: CoVar -> Name -> CoVar
    setCoVarName   = CoVar -> Name -> CoVar
    setVarName

    {-
    %************************************************************************
    %*                                                                      *
                       Pretty-printing CoAxioms
    %*                                                                      *
    %************************************************************************

    Defined here to avoid module loops. CoAxiom is loaded very early on.

    -}

    etaExpandCoAxBranch :: CoAxBranch -> ([TyVar], [Type], Type)
    -- Return the (tvs,lhs,rhs) after eta-expanding,
    -- to the way in which the axiom was originally written
    -- See Note [Eta reduction for data families] in GHC.Core.Coercion.Axiom
    etaExpandCoAxBranch :: CoAxBranch -> ([CoVar], [Type], Type)
    etaExpandCoAxBranch (CoAxBranch { cab_tvs :: CoAxBranch -> [CoVar]
    cab_tvs = [CoVar]
    tvs
                                    , cab_eta_tvs :: CoAxBranch -> [CoVar]
    cab_eta_tvs = [CoVar]
    eta_tvs
                                    , cab_lhs :: CoAxBranch -> [Type]
    cab_lhs = [Type]
    lhs
                                    , cab_rhs :: CoAxBranch -> Type
    cab_rhs = Type
    rhs })
      -- ToDo: what about eta_cvs?
      = ([CoVar]
    tvs [CoVar] -> [CoVar] -> [CoVar]
    forall a. [a] -> [a] -> [a]
    ++ [CoVar]
    eta_tvs, [Type]
    lhs [Type] -> [Type] -> [Type]
    forall a. [a] -> [a] -> [a]
    ++ [Type]
    eta_tys, Type -> [Type] -> Type
    mkAppTys Type
    rhs [Type]
    eta_tys)
     where
        eta_tys :: [Type]
    eta_tys = [CoVar] -> [Type]
    mkTyVarTys [CoVar]
    eta_tvs

    pprCoAxiom :: CoAxiom br -> SDoc
    -- Used in debug-printing only
    pprCoAxiom :: forall (br :: BranchFlag). CoAxiom br -> SDoc
    pprCoAxiom ax :: CoAxiom br
    ax@(CoAxiom { co_ax_tc :: forall (br :: BranchFlag). CoAxiom br -> TyCon
    co_ax_tc = TyCon
    tc, co_ax_branches :: forall (br :: BranchFlag). CoAxiom br -> Branches br
    co_ax_branches = Branches br
    branches })
      = SDoc -> Arity -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "axiom" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> CoAxiom br -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoAxiom br
    ax)
           Arity
    2 (SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc
    braces (SDoc -> SDoc) -> SDoc -> SDoc
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat ((CoAxBranch -> SDoc) -> [CoAxBranch] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map (TyCon -> CoAxBranch -> SDoc
    pprCoAxBranchUser TyCon
    tc) (Branches br -> [CoAxBranch]
    forall (br :: BranchFlag). Branches br -> [CoAxBranch]
    fromBranches Branches br
    branches)))

    pprCoAxBranchUser :: TyCon -> CoAxBranch -> SDoc
    -- Used when printing injectivity errors (FamInst.reportInjectivityErrors)
    -- and inaccessible branches (GHC.Tc.Validity.inaccessibleCoAxBranch)
    -- This happens in error messages: don't print the RHS of a data
    --   family axiom, which is meaningless to a user
    pprCoAxBranchUser :: TyCon -> CoAxBranch -> SDoc
    pprCoAxBranchUser TyCon
    tc CoAxBranch
    br
      | TyCon -> Bool
    isDataFamilyTyCon TyCon
    tc = TyCon -> CoAxBranch -> SDoc
    pprCoAxBranchLHS TyCon
    tc CoAxBranch
    br
      | Bool
    otherwise            = TyCon -> CoAxBranch -> SDoc
    pprCoAxBranch    TyCon
    tc CoAxBranch
    br

    pprCoAxBranchLHS :: TyCon -> CoAxBranch -> SDoc
    -- Print the family-instance equation when reporting
    --   a conflict between equations (FamInst.conflictInstErr)
    -- For type families the RHS is important; for data families not so.
    --   Indeed for data families the RHS is a mysterious internal
    --   type constructor, so we suppress it (#14179)
    -- See FamInstEnv Note [Family instance overlap conflicts]
    pprCoAxBranchLHS :: TyCon -> CoAxBranch -> SDoc
    pprCoAxBranchLHS = (TidyEnv -> Type -> SDoc) -> TyCon -> CoAxBranch -> SDoc
    ppr_co_ax_branch TidyEnv -> Type -> SDoc
    forall {doc} {p} {p}. IsOutput doc => p -> p -> doc
    pp_rhs
      where
        pp_rhs :: p -> p -> doc
    pp_rhs p
    _ p
    _ = doc
    forall doc. IsOutput doc => doc
    empty

    pprCoAxBranch :: TyCon -> CoAxBranch -> SDoc
    pprCoAxBranch :: TyCon -> CoAxBranch -> SDoc
    pprCoAxBranch = (TidyEnv -> Type -> SDoc) -> TyCon -> CoAxBranch -> SDoc
    ppr_co_ax_branch TidyEnv -> Type -> SDoc
    ppr_rhs
      where
        ppr_rhs :: TidyEnv -> Type -> SDoc
    ppr_rhs TidyEnv
    env Type
    rhs = SDoc
    forall doc. IsLine doc => doc
    equals SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> TidyEnv -> PprPrec -> Type -> SDoc
    pprPrecTypeX TidyEnv
    env PprPrec
    topPrec Type
    rhs

    ppr_co_ax_branch :: (TidyEnv -> Type -> SDoc)
                     -> TyCon -> CoAxBranch -> SDoc
    ppr_co_ax_branch :: (TidyEnv -> Type -> SDoc) -> TyCon -> CoAxBranch -> SDoc
    ppr_co_ax_branch TidyEnv -> Type -> SDoc
    ppr_rhs TyCon
    fam_tc CoAxBranch
    branch
      = (SDoc -> SDoc -> SDoc) -> [SDoc] -> SDoc
    forall a. (a -> a -> a) -> [a] -> a
    forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
    foldr1 ((SDoc -> Arity -> SDoc -> SDoc) -> Arity -> SDoc -> SDoc -> SDoc
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip SDoc -> Arity -> SDoc -> SDoc
    hangNotEmpty Arity
    2)
        [ [ForAllTyBinder] -> SDoc
    pprUserForAll (ForAllTyFlag -> [CoVar] -> [ForAllTyBinder]
    forall vis. vis -> [CoVar] -> [VarBndr CoVar vis]
    mkForAllTyBinders ForAllTyFlag
    Inferred [CoVar]
    bndrs')
             -- See Note [Printing foralls in type family instances] in GHC.Iface.Type
        , SDoc
    pp_lhs SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> TidyEnv -> Type -> SDoc
    ppr_rhs TidyEnv
    tidy_env Type
    ee_rhs
        , [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "-- Defined" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SDoc
    pp_loc
               , Bool -> SDoc -> SDoc
    forall doc. IsOutput doc => Bool -> doc -> doc
    ppUnless ([CoAxBranch] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [CoAxBranch]
    incomps) (SDoc -> SDoc) -> SDoc -> SDoc
    forall a b. (a -> b) -> a -> b
    $ SDoc -> SDoc
    forall doc. IsOutput doc => doc -> doc
    whenPprDebug (SDoc -> SDoc) -> SDoc -> SDoc
    forall a b. (a -> b) -> a -> b
    $
                 String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "-- Incomps:" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat ((CoAxBranch -> SDoc) -> [CoAxBranch] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map (TyCon -> CoAxBranch -> SDoc
    pprCoAxBranch TyCon
    fam_tc) [CoAxBranch]
    incomps) ]
        ]
      where
        incomps :: [CoAxBranch]
    incomps = CoAxBranch -> [CoAxBranch]
    coAxBranchIncomps CoAxBranch
    branch
        loc :: SrcSpan
    loc = CoAxBranch -> SrcSpan
    coAxBranchSpan CoAxBranch
    branch
        pp_loc :: SDoc
    pp_loc | SrcSpan -> Bool
    isGoodSrcSpan SrcSpan
    loc = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "at" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SrcLoc -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (SrcSpan -> SrcLoc
    srcSpanStart SrcSpan
    loc)
               | Bool
    otherwise         = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "in" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SrcSpan -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr SrcSpan
    loc

        -- Eta-expand LHS and RHS types, because sometimes data family
        -- instances are eta-reduced.
        -- See Note [Eta reduction for data families] in GHC.Core.Coercion.Axiom.
        ([CoVar]
    ee_tvs, [Type]
    ee_lhs, Type
    ee_rhs) = CoAxBranch -> ([CoVar], [Type], Type)
    etaExpandCoAxBranch CoAxBranch
    branch

        pp_lhs :: SDoc
    pp_lhs = PprPrec -> IfaceTyCon -> IfaceAppArgs -> SDoc
    pprIfaceTypeApp PprPrec
    topPrec (TyCon -> IfaceTyCon
    toIfaceTyCon TyCon
    fam_tc)
                                 (TidyEnv -> TyCon -> [Type] -> IfaceAppArgs
    tidyToIfaceTcArgs TidyEnv
    tidy_env TyCon
    fam_tc [Type]
    ee_lhs)

        (TidyEnv
    tidy_env, [CoVar]
    bndrs') = TidyEnv -> [CoVar] -> (TidyEnv, [CoVar])
    tidyCoAxBndrsForUser TidyEnv
    emptyTidyEnv [CoVar]
    ee_tvs

    tidyCoAxBndrsForUser :: TidyEnv -> [Var] -> (TidyEnv, [Var])
    -- Tidy wildcards "_1", "_2" to "_", and do not return them
    -- in the list of binders to be printed
    -- This is so that in error messages we see
    --     forall a. F _ [a] _ = ...
    -- rather than
    --     forall a _1 _2. F _1 [a] _2 = ...
    --
    -- This is a rather disgusting function
    -- See Note [Wildcard names] in GHC.Tc.Gen.HsType
    tidyCoAxBndrsForUser :: TidyEnv -> [CoVar] -> (TidyEnv, [CoVar])
    tidyCoAxBndrsForUser TidyEnv
    init_env [CoVar]
    tcvs
      = (TidyEnv
    tidy_env, [CoVar] -> [CoVar]
    forall a. [a] -> [a]
    reverse [CoVar]
    tidy_bndrs)
      where
        (TidyEnv
    tidy_env, [CoVar]
    tidy_bndrs) = ((TidyEnv, [CoVar]) -> CoVar -> (TidyEnv, [CoVar]))
    -> (TidyEnv, [CoVar]) -> [CoVar] -> (TidyEnv, [CoVar])
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl (TidyEnv, [CoVar]) -> CoVar -> (TidyEnv, [CoVar])
    tidy_one (TidyEnv
    init_env, []) [CoVar]
    tcvs

        tidy_one :: (TidyEnv, [CoVar]) -> CoVar -> (TidyEnv, [CoVar])
    tidy_one (env :: TidyEnv
    env@(TidyOccEnv
    occ_env, VarEnv CoVar
    subst), [CoVar]
    rev_bndrs') CoVar
    bndr
          | CoVar -> Bool
    is_wildcard CoVar
    bndr = (TidyEnv
    env_wild, [CoVar]
    rev_bndrs')
          | Bool
    otherwise        = (TidyEnv
    env',     CoVar
    bndr' CoVar -> [CoVar] -> [CoVar]
    forall a. a -> [a] -> [a]
    : [CoVar]
    rev_bndrs')
          where
            (TidyEnv
    env', CoVar
    bndr') = TidyEnv -> CoVar -> (TidyEnv, CoVar)
    tidyVarBndr TidyEnv
    env CoVar
    bndr
            env_wild :: TidyEnv
    env_wild = (TidyOccEnv
    occ_env, VarEnv CoVar -> CoVar -> CoVar -> VarEnv CoVar
    forall a. VarEnv a -> CoVar -> a -> VarEnv a
    extendVarEnv VarEnv CoVar
    subst CoVar
    bndr CoVar
    wild_bndr)
            wild_bndr :: CoVar
    wild_bndr = CoVar -> Name -> CoVar
    setVarName CoVar
    bndr (Name -> CoVar) -> Name -> CoVar
    forall a b. (a -> b) -> a -> b
    $
                        Name -> OccName -> Name
    tidyNameOcc (CoVar -> Name
    varName CoVar
    bndr) (FastString -> OccName
    mkTyVarOccFS (String -> FastString
    fsLit String
    "_"))
                        -- Tidy the binder to "_"

        is_wildcard :: Var -> Bool
        is_wildcard :: CoVar -> Bool
    is_wildcard CoVar
    tv = case OccName -> String
    occNameString (CoVar -> OccName
    forall a. NamedThing a => a -> OccName
    getOccName CoVar
    tv) of
                           (Char
    '_' : String
    rest) -> (Char -> Bool) -> String -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Char -> Bool
    isDigit String
    rest
                           String
    _            -> Bool
    False

    {- *********************************************************************
    *                                                                      *
                  MCoercion
    *                                                                      *
    ********************************************************************* -}

    coToMCo :: Coercion -> MCoercion
    -- Convert a coercion to a MCoercion,
    -- It's not clear whether or not isReflexiveCo would be better here
    --    See #19815 for a bit of data and discussion on this point
    coToMCo :: Coercion -> MCoercion
    coToMCo Coercion
    co | Coercion -> Bool
    isReflCo Coercion
    co = MCoercion
    MRefl
               | Bool
    otherwise   = Coercion -> MCoercion
    MCo Coercion
    co

    checkReflexiveMCo :: MCoercion -> MCoercion
    checkReflexiveMCo :: MCoercion -> MCoercion
    checkReflexiveMCo MCoercion
    MRefl                       = MCoercion
    MRefl
    checkReflexiveMCo (MCo Coercion
    co) | Coercion -> Bool
    isReflexiveCo Coercion
    co = MCoercion
    MRefl
                               | Bool
    otherwise        = Coercion -> MCoercion
    MCo Coercion
    co

    -- | Tests if this MCoercion is obviously generalized reflexive
    -- Guaranteed to work very quickly.
    isGReflMCo :: MCoercion -> Bool
    isGReflMCo :: MCoercion -> Bool
    isGReflMCo MCoercion
    MRefl = Bool
    True
    isGReflMCo (MCo Coercion
    co) | Coercion -> Bool
    isGReflCo Coercion
    co = Bool
    True
    isGReflMCo MCoercion
    _ = Bool
    False

    -- | Make a generalized reflexive coercion
    mkGReflCo :: Role -> Type -> MCoercionN -> Coercion
    mkGReflCo :: Role -> Type -> MCoercion -> Coercion
    mkGReflCo Role
    r Type
    ty MCoercion
    mco
      | MCoercion -> Bool
    isGReflMCo MCoercion
    mco = if Role
    r Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role
    Nominal then Type -> Coercion
    Refl Type
    ty
                         else Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty MCoercion
    MRefl
      | Bool
    otherwise    = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty MCoercion
    mco

    -- | Compose two MCoercions via transitivity
    mkTransMCo :: MCoercion -> MCoercion -> MCoercion
    mkTransMCo :: MCoercion -> MCoercion -> MCoercion
    mkTransMCo MCoercion
    MRefl     MCoercion
    co2       = MCoercion
    co2
    mkTransMCo MCoercion
    co1       MCoercion
    MRefl     = MCoercion
    co1
    mkTransMCo (MCo Coercion
    co1) (MCo Coercion
    co2) = Coercion -> MCoercion
    MCo (Coercion -> Coercion -> Coercion
    mkTransCo Coercion
    co1 Coercion
    co2)

    mkTransMCoL :: MCoercion -> Coercion -> MCoercion
    mkTransMCoL :: MCoercion -> Coercion -> MCoercion
    mkTransMCoL MCoercion
    MRefl     Coercion
    co2 = Coercion -> MCoercion
    coToMCo Coercion
    co2
    mkTransMCoL (MCo Coercion
    co1) Coercion
    co2 = Coercion -> MCoercion
    MCo (Coercion -> Coercion -> Coercion
    mkTransCo Coercion
    co1 Coercion
    co2)

    mkTransMCoR :: Coercion -> MCoercion -> MCoercion
    mkTransMCoR :: Coercion -> MCoercion -> MCoercion
    mkTransMCoR Coercion
    co1 MCoercion
    MRefl     = Coercion -> MCoercion
    coToMCo Coercion
    co1
    mkTransMCoR Coercion
    co1 (MCo Coercion
    co2) = Coercion -> MCoercion
    MCo (Coercion -> Coercion -> Coercion
    mkTransCo Coercion
    co1 Coercion
    co2)

    -- | Get the reverse of an 'MCoercion'
    mkSymMCo :: MCoercion -> MCoercion
    mkSymMCo :: MCoercion -> MCoercion
    mkSymMCo MCoercion
    MRefl    = MCoercion
    MRefl
    mkSymMCo (MCo Coercion
    co) = Coercion -> MCoercion
    MCo (Coercion -> Coercion
    mkSymCo Coercion
    co)

    -- | Cast a type by an 'MCoercion'
    mkCastTyMCo :: Type -> MCoercion -> Type
    mkCastTyMCo :: Type -> MCoercion -> Type
    mkCastTyMCo Type
    ty MCoercion
    MRefl    = Type
    ty
    mkCastTyMCo Type
    ty (MCo Coercion
    co) = Type
    ty Type -> Coercion -> Type
    `mkCastTy` Coercion
    co

    mkHomoForAllMCo :: TyCoVar -> MCoercion -> MCoercion
    mkHomoForAllMCo :: CoVar -> MCoercion -> MCoercion
    mkHomoForAllMCo CoVar
    _   MCoercion
    MRefl    = MCoercion
    MRefl
    mkHomoForAllMCo CoVar
    tcv (MCo Coercion
    co) = Coercion -> MCoercion
    MCo ([CoVar] -> Coercion -> Coercion
    mkHomoForAllCos [CoVar
    tcv] Coercion
    co)

    mkPiMCos :: [Var] -> MCoercion -> MCoercion
    mkPiMCos :: [CoVar] -> MCoercion -> MCoercion
    mkPiMCos [CoVar]
    _ MCoercion
    MRefl = MCoercion
    MRefl
    mkPiMCos [CoVar]
    vs (MCo Coercion
    co) = Coercion -> MCoercion
    MCo (Role -> [CoVar] -> Coercion -> Coercion
    mkPiCos Role
    Representational [CoVar]
    vs Coercion
    co)

    mkFunResMCo :: Id -> MCoercionR -> MCoercionR
    mkFunResMCo :: CoVar -> MCoercion -> MCoercion
    mkFunResMCo CoVar
    _      MCoercion
    MRefl    = MCoercion
    MRefl
    mkFunResMCo CoVar
    arg_id (MCo Coercion
    co) = Coercion -> MCoercion
    MCo (Role -> CoVar -> Coercion -> Coercion
    mkFunResCo Role
    Representational CoVar
    arg_id Coercion
    co)

    mkGReflLeftMCo :: Role -> Type -> MCoercionN -> Coercion
    mkGReflLeftMCo :: Role -> Type -> MCoercion -> Coercion
    mkGReflLeftMCo Role
    r Type
    ty MCoercion
    MRefl    = Role -> Type -> Coercion
    mkReflCo Role
    r Type
    ty
    mkGReflLeftMCo Role
    r Type
    ty (MCo Coercion
    co) = Role -> Type -> Coercion -> Coercion
    mkGReflLeftCo Role
    r Type
    ty Coercion
    co

    mkGReflRightMCo :: Role -> Type -> MCoercionN -> Coercion
    mkGReflRightMCo :: Role -> Type -> MCoercion -> Coercion
    mkGReflRightMCo Role
    r Type
    ty MCoercion
    MRefl    = Role -> Type -> Coercion
    mkReflCo Role
    r Type
    ty
    mkGReflRightMCo Role
    r Type
    ty (MCo Coercion
    co) = Role -> Type -> Coercion -> Coercion
    mkGReflRightCo Role
    r Type
    ty Coercion
    co

    -- | Like 'mkCoherenceRightCo', but with an 'MCoercion'
    mkCoherenceRightMCo :: Role -> Type -> MCoercionN -> Coercion -> Coercion
    mkCoherenceRightMCo :: Role -> Type -> MCoercion -> Coercion -> Coercion
    mkCoherenceRightMCo Role
    _ Type
    _  MCoercion
    MRefl    Coercion
    co2 = Coercion
    co2
    mkCoherenceRightMCo Role
    r Type
    ty (MCo Coercion
    co) Coercion
    co2 = Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceRightCo Role
    r Type
    ty Coercion
    co Coercion
    co2

    isReflMCo :: MCoercion -> Bool
    isReflMCo :: MCoercion -> Bool
    isReflMCo MCoercion
    MRefl = Bool
    True
    isReflMCo MCoercion
    _     = Bool
    False

    {-
    %************************************************************************
    %*                                                                      *
            Destructing coercions
    %*                                                                      *
    %************************************************************************
    -}

    -- | This breaks a 'Coercion' with type @T A B C ~ T D E F@ into
    -- a list of 'Coercion's of kinds @A ~ D@, @B ~ E@ and @E ~ F@. Hence:
    --
    -- > decomposeCo 3 c [r1, r2, r3] = [nth r1 0 c, nth r2 1 c, nth r3 2 c]
    decomposeCo :: Arity -> Coercion
                -> Infinite Role  -- the roles of the output coercions
                -> [Coercion]
    decomposeCo :: Arity -> Coercion -> Infinite Role -> [Coercion]
    decomposeCo Arity
    arity Coercion
    co Infinite Role
    rs
      = [(() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    n Role
    r) Coercion
    co | (Arity
    n,Role
    r) <- [Arity
    0..(Arity
    arityArity -> Arity -> Arity
    forall a. Num a => a -> a -> a
    -Arity
    1)] [Arity] -> [Role] -> [(Arity, Role)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` Infinite Role -> [Role]
    forall a. Infinite a -> [a]
    Inf.toList Infinite Role
    rs ]
         -- Remember, SelTyCon is zero-indexed

    decomposeFunCo :: HasDebugCallStack
                   => Coercion  -- Input coercion
                   -> (CoercionN, Coercion, Coercion)
    -- Expects co :: (s1 %m1-> t1) ~ (s2 %m2-> t2)
    -- Returns (cow :: m1 ~N m2, co1 :: s1~s2, co2 :: t1~t2)
    -- actually cow will be a Phantom coercion if the input is a Phantom coercion

    decomposeFunCo :: (() :: Constraint) => Coercion -> (Coercion, Coercion, Coercion)
    decomposeFunCo (FunCo { fco_mult :: Coercion -> Coercion
    fco_mult = Coercion
    w, fco_arg :: Coercion -> Coercion
    fco_arg = Coercion
    co1, fco_res :: Coercion -> Coercion
    fco_res = Coercion
    co2 })
      = (Coercion
    w, Coercion
    co1, Coercion
    co2)
       -- Short-circuits the calls to mkSelCo

    decomposeFunCo Coercion
    co
      = Bool
    -> SDoc
    -> (Coercion, Coercion, Coercion)
    -> (Coercion, Coercion, Coercion)
    forall a. HasCallStack => Bool -> SDoc -> a -> a
    assertPpr Bool
    all_ok (Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    co) ((Coercion, Coercion, Coercion) -> (Coercion, Coercion, Coercion))
    -> (Coercion, Coercion, Coercion) -> (Coercion, Coercion, Coercion)
    forall a b. (a -> b) -> a -> b
    $
        ( (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (FunSel -> CoSel
    SelFun FunSel
    SelMult) Coercion
    co
        , (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (FunSel -> CoSel
    SelFun FunSel
    SelArg) Coercion
    co
        , (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (FunSel -> CoSel
    SelFun FunSel
    SelRes) Coercion
    co )
      where
        Pair Type
    s1t1 Type
    s2t2 = Coercion -> Pair Type
    coercionKind Coercion
    co
        all_ok :: Bool
    all_ok = Type -> Bool
    isFunTy Type
    s1t1 Bool -> Bool -> Bool
    && Type -> Bool
    isFunTy Type
    s2t2

    {- Note [Pushing a coercion into a pi-type]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Suppose we have this:
        (f |> co) t1 .. tn
    Then we want to push the coercion into the arguments, so as to make
    progress. For example of why you might want to do so, see Note
    [Respecting definitional equality] in GHC.Core.TyCo.Rep.

    This is done by decomposePiCos.  Specifically, if
        decomposePiCos co [t1,..,tn] = ([co1,...,cok], cor)
    then
        (f |> co) t1 .. tn   =   (f (t1 |> co1) ... (tk |> cok)) |> cor) t(k+1) ... tn

    Notes:

    * k can be smaller than n! That is decomposePiCos can return *fewer*
      coercions than there are arguments (ie k < n), if the kind provided
      doesn't have enough binders.

    * If there is a type error, we might see
           (f |> co) t1
      where co :: (forall a. ty) ~ (ty1 -> ty2)
      Here 'co' is insoluble, but we don't want to crash in decoposePiCos.
      So decomposePiCos carefully tests both sides of the coercion to check
      they are both foralls or both arrows.  Not doing this caused #15343.
    -}

    decomposePiCos :: HasDebugCallStack
                   => CoercionN -> Pair Type  -- Coercion and its kind
                   -> [Type]
                   -> ([CoercionN], CoercionN)
    -- See Note [Pushing a coercion into a pi-type]
    decomposePiCos :: (() :: Constraint) =>
    Coercion -> Pair Type -> [Type] -> ([Coercion], Coercion)
    decomposePiCos Coercion
    orig_co (Pair Type
    orig_k1 Type
    orig_k2) [Type]
    orig_args
      = [Coercion]
    -> (Subst, Type)
    -> Coercion
    -> (Subst, Type)
    -> [Type]
    -> ([Coercion], Coercion)
    go [] (Subst
    orig_subst,Type
    orig_k1) Coercion
    orig_co (Subst
    orig_subst,Type
    orig_k2) [Type]
    orig_args
      where
        orig_subst :: Subst
    orig_subst = InScopeSet -> Subst
    mkEmptySubst (InScopeSet -> Subst) -> InScopeSet -> Subst
    forall a b. (a -> b) -> a -> b
    $ VarSet -> InScopeSet
    mkInScopeSet (VarSet -> InScopeSet) -> VarSet -> InScopeSet
    forall a b. (a -> b) -> a -> b
    $
                     [Type] -> VarSet
    tyCoVarsOfTypes [Type]
    orig_args VarSet -> VarSet -> VarSet
    `unionVarSet` Coercion -> VarSet
    tyCoVarsOfCo Coercion
    orig_co

        go :: [CoercionN]      -- accumulator for argument coercions, reversed
           -> (Subst,Kind)  -- Lhs kind of coercion
           -> CoercionN        -- coercion originally applied to the function
           -> (Subst,Kind)  -- Rhs kind of coercion
           -> [Type]           -- Arguments to that function
           -> ([CoercionN], Coercion)
        -- Invariant:  co :: subst1(k1) ~ subst2(k2)

        go :: [Coercion]
    -> (Subst, Type)
    -> Coercion
    -> (Subst, Type)
    -> [Type]
    -> ([Coercion], Coercion)
    go [Coercion]
    acc_arg_cos (Subst
    subst1,Type
    k1) Coercion
    co (Subst
    subst2,Type
    k2) (Type
    ty:[Type]
    tys)
          | Just (CoVar
    a, Type
    t1) <- Type -> Maybe (CoVar, Type)
    splitForAllTyCoVar_maybe Type
    k1
          , Just (CoVar
    b, Type
    t2) <- Type -> Maybe (CoVar, Type)
    splitForAllTyCoVar_maybe Type
    k2
            -- know     co :: (forall a:s1.t1) ~ (forall b:s2.t2)
            --    function :: forall a:s1.t1   (the function is not passed to decomposePiCos)
            --           a :: s1
            --           b :: s2
            --          ty :: s2
            -- need arg_co :: s2 ~ s1
            --      res_co :: t1[ty |> arg_co / a] ~ t2[ty / b]
          = let arg_co :: Coercion
    arg_co  = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo CoSel
    SelForAll (Coercion -> Coercion
    mkSymCo Coercion
    co)
                res_co :: Coercion
    res_co  = Coercion -> Coercion -> Coercion
    mkInstCo Coercion
    co (Role -> Type -> Coercion -> Coercion
    mkGReflLeftCo Role
    Nominal Type
    ty Coercion
    arg_co)
                subst1' :: Subst
    subst1' = Subst -> CoVar -> Type -> Subst
    extendTCvSubst Subst
    subst1 CoVar
    a (Type
    ty Type -> Coercion -> Type
    `CastTy` Coercion
    arg_co)
                subst2' :: Subst
    subst2' = Subst -> CoVar -> Type -> Subst
    extendTCvSubst Subst
    subst2 CoVar
    b Type
    ty
            in
            [Coercion]
    -> (Subst, Type)
    -> Coercion
    -> (Subst, Type)
    -> [Type]
    -> ([Coercion], Coercion)
    go (Coercion
    arg_co Coercion -> [Coercion] -> [Coercion]
    forall a. a -> [a] -> [a]
    : [Coercion]
    acc_arg_cos) (Subst
    subst1', Type
    t1) Coercion
    res_co (Subst
    subst2', Type
    t2) [Type]
    tys

          | Just (FunTyFlag
    af1, Type
    _w1, Type
    _s1, Type
    t1) <- Type -> Maybe (FunTyFlag, Type, Type, Type)
    splitFunTy_maybe Type
    k1
          , Just (FunTyFlag
    af2, Type
    _w1, Type
    _s2, Type
    t2) <- Type -> Maybe (FunTyFlag, Type, Type, Type)
    splitFunTy_maybe Type
    k2
          , FunTyFlag
    af1 FunTyFlag -> FunTyFlag -> Bool
    forall a. Eq a => a -> a -> Bool
    == FunTyFlag
    af2  -- Same sort of arrow
            -- know     co :: (s1 -> t1) ~ (s2 -> t2)
            --    function :: s1 -> t1
            --          ty :: s2
            -- need arg_co :: s2 ~ s1
            --      res_co :: t1 ~ t2
          = let (Coercion
    _, Coercion
    sym_arg_co, Coercion
    res_co) = (() :: Constraint) => Coercion -> (Coercion, Coercion, Coercion)
    Coercion -> (Coercion, Coercion, Coercion)
    decomposeFunCo Coercion
    co
                -- It should be fine to ignore the multiplicity bit
                -- of the coercion for a Nominal coercion.
                arg_co :: Coercion
    arg_co = Coercion -> Coercion
    mkSymCo Coercion
    sym_arg_co
            in
            [Coercion]
    -> (Subst, Type)
    -> Coercion
    -> (Subst, Type)
    -> [Type]
    -> ([Coercion], Coercion)
    go (Coercion
    arg_co Coercion -> [Coercion] -> [Coercion]
    forall a. a -> [a] -> [a]
    : [Coercion]
    acc_arg_cos) (Subst
    subst1,Type
    t1) Coercion
    res_co (Subst
    subst2,Type
    t2) [Type]
    tys

          | Bool -> Bool
    not (Subst -> Bool
    isEmptyTCvSubst Subst
    subst1) Bool -> Bool -> Bool
    || Bool -> Bool
    not (Subst -> Bool
    isEmptyTCvSubst Subst
    subst2)
          = [Coercion]
    -> (Subst, Type)
    -> Coercion
    -> (Subst, Type)
    -> [Type]
    -> ([Coercion], Coercion)
    go [Coercion]
    acc_arg_cos (Subst -> Subst
    zapSubst Subst
    subst1, (() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy Subst
    subst1 Type
    k1)
                           Coercion
    co
                           (Subst -> Subst
    zapSubst Subst
    subst2, (() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy Subst
    subst1 Type
    k2)
                           (Type
    tyType -> [Type] -> [Type]
    forall a. a -> [a] -> [a]
    :[Type]
    tys)

          -- tys might not be empty, if the left-hand type of the original coercion
          -- didn't have enough binders
        go [Coercion]
    acc_arg_cos (Subst, Type)
    _ki1 Coercion
    co (Subst, Type)
    _ki2 [Type]
    _tys = ([Coercion] -> [Coercion]
    forall a. [a] -> [a]
    reverse [Coercion]
    acc_arg_cos, Coercion
    co)

    -- | Extract a covar, if possible. This check is dirty. Be ashamed
    -- of yourself. (It's dirty because it cares about the structure of
    -- a coercion, which is morally reprehensible.)
    getCoVar_maybe :: Coercion -> Maybe CoVar
    getCoVar_maybe :: Coercion -> Maybe CoVar
    getCoVar_maybe (CoVarCo CoVar
    cv) = CoVar -> Maybe CoVar
    forall a. a -> Maybe a
    Just CoVar
    cv
    getCoVar_maybe Coercion
    _            = Maybe CoVar
    forall a. Maybe a
    Nothing

    multToCo :: Mult -> Coercion
    multToCo :: Type -> Coercion
    multToCo Type
    r = Type -> Coercion
    mkNomReflCo Type
    r

    -- first result has role equal to input; third result is Nominal
    splitAppCo_maybe :: Coercion -> Maybe (Coercion, Coercion)
    -- ^ Attempt to take a coercion application apart.
    splitAppCo_maybe :: Coercion -> Maybe (Coercion, Coercion)
    splitAppCo_maybe (AppCo Coercion
    co Coercion
    arg) = (Coercion, Coercion) -> Maybe (Coercion, Coercion)
    forall a. a -> Maybe a
    Just (Coercion
    co, Coercion
    arg)
    splitAppCo_maybe (TyConAppCo Role
    r TyCon
    tc [Coercion]
    args)
      | [Coercion]
    args [Coercion] -> Arity -> Bool
    forall a. [a] -> Arity -> Bool
    `lengthExceeds` TyCon -> Arity
    tyConArity TyCon
    tc
      , Just ([Coercion]
    args', Coercion
    arg') <- [Coercion] -> Maybe ([Coercion], Coercion)
    forall a. [a] -> Maybe ([a], a)
    snocView [Coercion]
    args
      = (Coercion, Coercion) -> Maybe (Coercion, Coercion)
    forall a. a -> Maybe a
    Just ( (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    r TyCon
    tc [Coercion]
    args', Coercion
    arg' )

      | Bool -> Bool
    not (TyCon -> Bool
    tyConMustBeSaturated TyCon
    tc)
        -- Never create unsaturated type family apps!
      , Just ([Coercion]
    args', Coercion
    arg') <- [Coercion] -> Maybe ([Coercion], Coercion)
    forall a. [a] -> Maybe ([a], a)
    snocView [Coercion]
    args
      , Just Coercion
    arg'' <- Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe (Role -> TyCon -> Arity -> Role
    tyConRole Role
    r TyCon
    tc ([Coercion] -> Arity
    forall a. [a] -> Arity
    forall (t :: * -> *) a. Foldable t => t a -> Arity
    length [Coercion]
    args')) Coercion
    arg'
      = (Coercion, Coercion) -> Maybe (Coercion, Coercion)
    forall a. a -> Maybe a
    Just ( (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    r TyCon
    tc [Coercion]
    args', Coercion
    arg'' )
           -- Use mkTyConAppCo to preserve the invariant
           --  that identity coercions are always represented by Refl

    splitAppCo_maybe Coercion
    co
      | Just (Type
    ty, Role
    r) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      , Just (Type
    ty1, Type
    ty2) <- Type -> Maybe (Type, Type)
    splitAppTy_maybe Type
    ty
      = (Coercion, Coercion) -> Maybe (Coercion, Coercion)
    forall a. a -> Maybe a
    Just (Role -> Type -> Coercion
    mkReflCo Role
    r Type
    ty1, Type -> Coercion
    mkNomReflCo Type
    ty2)
    splitAppCo_maybe Coercion
    _ = Maybe (Coercion, Coercion)
    forall a. Maybe a
    Nothing

    -- Only used in specialise/Rules
    splitFunCo_maybe :: Coercion -> Maybe (Coercion, Coercion)
    splitFunCo_maybe :: Coercion -> Maybe (Coercion, Coercion)
    splitFunCo_maybe (FunCo { fco_arg :: Coercion -> Coercion
    fco_arg = Coercion
    arg, fco_res :: Coercion -> Coercion
    fco_res = Coercion
    res }) = (Coercion, Coercion) -> Maybe (Coercion, Coercion)
    forall a. a -> Maybe a
    Just (Coercion
    arg, Coercion
    res)
    splitFunCo_maybe Coercion
    _ = Maybe (Coercion, Coercion)
    forall a. Maybe a
    Nothing

    splitForAllCo_maybe :: Coercion -> Maybe (TyCoVar, Coercion, Coercion)
    splitForAllCo_maybe :: Coercion -> Maybe (CoVar, Coercion, Coercion)
    splitForAllCo_maybe (ForAllCo CoVar
    tv Coercion
    k_co Coercion
    co) = (CoVar, Coercion, Coercion) -> Maybe (CoVar, Coercion, Coercion)
    forall a. a -> Maybe a
    Just (CoVar
    tv, Coercion
    k_co, Coercion
    co)
    splitForAllCo_maybe Coercion
    _                     = Maybe (CoVar, Coercion, Coercion)
    forall a. Maybe a
    Nothing

    -- | Like 'splitForAllCo_maybe', but only returns Just for tyvar binder
    splitForAllCo_ty_maybe :: Coercion -> Maybe (TyVar, Coercion, Coercion)
    splitForAllCo_ty_maybe :: Coercion -> Maybe (CoVar, Coercion, Coercion)
    splitForAllCo_ty_maybe (ForAllCo CoVar
    tv Coercion
    k_co Coercion
    co)
      | CoVar -> Bool
    isTyVar CoVar
    tv = (CoVar, Coercion, Coercion) -> Maybe (CoVar, Coercion, Coercion)
    forall a. a -> Maybe a
    Just (CoVar
    tv, Coercion
    k_co, Coercion
    co)
    splitForAllCo_ty_maybe Coercion
    _ = Maybe (CoVar, Coercion, Coercion)
    forall a. Maybe a
    Nothing

    -- | Like 'splitForAllCo_maybe', but only returns Just for covar binder
    splitForAllCo_co_maybe :: Coercion -> Maybe (CoVar, Coercion, Coercion)
    splitForAllCo_co_maybe :: Coercion -> Maybe (CoVar, Coercion, Coercion)
    splitForAllCo_co_maybe (ForAllCo CoVar
    cv Coercion
    k_co Coercion
    co)
      | CoVar -> Bool
    isCoVar CoVar
    cv = (CoVar, Coercion, Coercion) -> Maybe (CoVar, Coercion, Coercion)
    forall a. a -> Maybe a
    Just (CoVar
    cv, Coercion
    k_co, Coercion
    co)
    splitForAllCo_co_maybe Coercion
    _ = Maybe (CoVar, Coercion, Coercion)
    forall a. Maybe a
    Nothing

    -------------------------------------------------------
    -- and some coercion kind stuff

    coVarLType, coVarRType :: HasDebugCallStack => CoVar -> Type
    coVarLType :: (() :: Constraint) => CoVar -> Type
    coVarLType CoVar
    cv | (Type
    _, Type
    _, Type
    ty1, Type
    _, Role
    _) <- (() :: Constraint) => CoVar -> (Type, Type, Type, Type, Role)
    CoVar -> (Type, Type, Type, Type, Role)
    coVarKindsTypesRole CoVar
    cv = Type
    ty1
    coVarRType :: (() :: Constraint) => CoVar -> Type
    coVarRType CoVar
    cv | (Type
    _, Type
    _, Type
    _, Type
    ty2, Role
    _) <- (() :: Constraint) => CoVar -> (Type, Type, Type, Type, Role)
    CoVar -> (Type, Type, Type, Type, Role)
    coVarKindsTypesRole CoVar
    cv = Type
    ty2

    coVarTypes :: HasDebugCallStack => CoVar -> Pair Type
    coVarTypes :: (() :: Constraint) => CoVar -> Pair Type
    coVarTypes CoVar
    cv
      | (Type
    _, Type
    _, Type
    ty1, Type
    ty2, Role
    _) <- (() :: Constraint) => CoVar -> (Type, Type, Type, Type, Role)
    CoVar -> (Type, Type, Type, Type, Role)
    coVarKindsTypesRole CoVar
    cv
      = Type -> Type -> Pair Type
    forall a. a -> a -> Pair a
    Pair Type
    ty1 Type
    ty2

    coVarKindsTypesRole :: HasDebugCallStack => CoVar -> (Kind,Kind,Type,Type,Role)
    coVarKindsTypesRole :: (() :: Constraint) => CoVar -> (Type, Type, Type, Type, Role)
    coVarKindsTypesRole CoVar
    cv
     | Just (TyCon
    tc, [Type
    k1,Type
    k2,Type
    ty1,Type
    ty2]) <- (() :: Constraint) => Type -> Maybe (TyCon, [Type])
    Type -> Maybe (TyCon, [Type])
    splitTyConApp_maybe (CoVar -> Type
    varType CoVar
    cv)
     = (Type
    k1, Type
    k2, Type
    ty1, Type
    ty2, TyCon -> Role
    eqTyConRole TyCon
    tc)
     | Bool
    otherwise
     = String -> SDoc -> (Type, Type, Type, Type, Role)
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "coVarKindsTypesRole, non coercion variable"
                (CoVar -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoVar
    cv SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (CoVar -> Type
    varType CoVar
    cv))

    coVarKind :: CoVar -> Type
    coVarKind :: CoVar -> Type
    coVarKind CoVar
    cv
      = Bool -> (CoVar -> Type) -> CoVar -> Type
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isCoVar CoVar
    cv )
        CoVar -> Type
    varType CoVar
    cv

    coVarRole :: CoVar -> Role
    coVarRole :: CoVar -> Role
    coVarRole CoVar
    cv
      = TyCon -> Role
    eqTyConRole (case Type -> Maybe TyCon
    tyConAppTyCon_maybe (CoVar -> Type
    varType CoVar
    cv) of
                       Just TyCon
    tc0 -> TyCon
    tc0
                       Maybe TyCon
    Nothing  -> String -> SDoc -> TyCon
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "coVarRole: not tyconapp" (CoVar -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoVar
    cv))

    eqTyConRole :: TyCon -> Role
    -- Given (~#) or (~R#) return the Nominal or Representational respectively
    eqTyConRole :: TyCon -> Role
    eqTyConRole TyCon
    tc
      | TyCon
    tc TyCon -> Unique -> Bool
    forall a. Uniquable a => a -> Unique -> Bool
    `hasKey` Unique
    eqPrimTyConKey
      = Role
    Nominal
      | TyCon
    tc TyCon -> Unique -> Bool
    forall a. Uniquable a => a -> Unique -> Bool
    `hasKey` Unique
    eqReprPrimTyConKey
      = Role
    Representational
      | Bool
    otherwise
      = String -> SDoc -> Role
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "eqTyConRole: unknown tycon" (TyCon -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr TyCon
    tc)

    -- | Given a coercion `co :: (t1 :: TYPE r1) ~ (t2 :: TYPE r2)`
    -- produce a coercion `rep_co :: r1 ~ r2`
    -- But actually it is possible that
    --     co :: (t1 :: CONSTRAINT r1) ~ (t2 :: CONSTRAINT r2)
    -- or  co :: (t1 :: TYPE r1)       ~ (t2 :: CONSTRAINT r2)
    -- or  co :: (t1 :: CONSTRAINT r1) ~ (t2 :: TYPE r2)
    -- See Note [mkRuntimeRepCo]
    mkRuntimeRepCo :: HasDebugCallStack => Coercion -> Coercion
    mkRuntimeRepCo :: (() :: Constraint) => Coercion -> Coercion
    mkRuntimeRepCo Coercion
    co
      = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Type -> Bool
    isTYPEorCONSTRAINT Type
    k1 Bool -> Bool -> Bool
    && Type -> Bool
    isTYPEorCONSTRAINT Type
    k2) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
        (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    0 Role
    Nominal) Coercion
    kind_co
      where
        kind_co :: Coercion
    kind_co = Coercion -> Coercion
    mkKindCo Coercion
    co  -- kind_co :: TYPE r1 ~ TYPE r2
        Pair Type
    k1 Type
    k2 = Coercion -> Pair Type
    coercionKind Coercion
    kind_co

    {- Note [mkRuntimeRepCo]
    ~~~~~~~~~~~~~~~~~~~~~~~~
    Given
       class C a where { op :: Maybe a }
    we will get an axiom
       axC a :: (C a :: CONSTRAINT r1) ~ (Maybe a :: TYPE r2)
    (See Note [Type and Constraint are not apart] in GHC.Builtin.Types.Prim.)

    Then we may call mkRuntimeRepCo on (axC ty), and that will return
       mkSelCo (SelTyCon 0 Nominal) (Kind (axC ty)) :: r1 ~ r2

    So mkSelCo needs to be happy with decomposing a coercion of kind
       CONSTRAINT r1 ~ TYPE r2

    Hence the use of `tyConIsTYPEorCONSTRAINT` in the assertion `good_call`
    in `mkSelCo`. See #23018 for a concrete example.  (In this context it's
    important that TYPE and CONSTRAINT have the same arity and kind, not
    merely that they are not-apart; otherwise SelCo would not make sense.)
    -}

    isReflCoVar_maybe :: Var -> Maybe Coercion
    -- If cv :: t~t then isReflCoVar_maybe cv = Just (Refl t)
    -- Works on all kinds of Vars, not just CoVars
    isReflCoVar_maybe :: CoVar -> Maybe Coercion
    isReflCoVar_maybe CoVar
    cv
      | CoVar -> Bool
    isCoVar CoVar
    cv
      , Pair Type
    ty1 Type
    ty2 <- (() :: Constraint) => CoVar -> Pair Type
    CoVar -> Pair Type
    coVarTypes CoVar
    cv
      , Type
    ty1 Type -> Type -> Bool
    `eqType` Type
    ty2
      = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Role -> Type -> Coercion
    mkReflCo (CoVar -> Role
    coVarRole CoVar
    cv) Type
    ty1)
      | Bool
    otherwise
      = Maybe Coercion
    forall a. Maybe a
    Nothing

    -- | Tests if this coercion is obviously a generalized reflexive coercion.
    -- Guaranteed to work very quickly.
    isGReflCo :: Coercion -> Bool
    isGReflCo :: Coercion -> Bool
    isGReflCo (GRefl{}) = Bool
    True
    isGReflCo (Refl{})  = Bool
    True -- Refl ty == GRefl N ty MRefl
    isGReflCo Coercion
    _         = Bool
    False

    -- | Tests if this coercion is obviously reflexive. Guaranteed to work
    -- very quickly. Sometimes a coercion can be reflexive, but not obviously
    -- so. c.f. 'isReflexiveCo'
    isReflCo :: Coercion -> Bool
    isReflCo :: Coercion -> Bool
    isReflCo (Refl{}) = Bool
    True
    isReflCo (GRefl Role
    _ Type
    _ MCoercion
    mco) | MCoercion -> Bool
    isGReflMCo MCoercion
    mco = Bool
    True
    isReflCo Coercion
    _ = Bool
    False

    -- | Returns the type coerced if this coercion is a generalized reflexive
    -- coercion. Guaranteed to work very quickly.
    isGReflCo_maybe :: Coercion -> Maybe (Type, Role)
    isGReflCo_maybe :: Coercion -> Maybe (Type, Role)
    isGReflCo_maybe (GRefl Role
    r Type
    ty MCoercion
    _) = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty, Role
    r)
    isGReflCo_maybe (Refl Type
    ty)      = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty, Role
    Nominal)
    isGReflCo_maybe Coercion
    _ = Maybe (Type, Role)
    forall a. Maybe a
    Nothing

    -- | Returns the type coerced if this coercion is reflexive. Guaranteed
    -- to work very quickly. Sometimes a coercion can be reflexive, but not
    -- obviously so. c.f. 'isReflexiveCo_maybe'
    isReflCo_maybe :: Coercion -> Maybe (Type, Role)
    isReflCo_maybe :: Coercion -> Maybe (Type, Role)
    isReflCo_maybe (Refl Type
    ty) = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty, Role
    Nominal)
    isReflCo_maybe (GRefl Role
    r Type
    ty MCoercion
    mco) | MCoercion -> Bool
    isGReflMCo MCoercion
    mco = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty, Role
    r)
    isReflCo_maybe Coercion
    _ = Maybe (Type, Role)
    forall a. Maybe a
    Nothing

    -- | Slowly checks if the coercion is reflexive. Don't call this in a loop,
    -- as it walks over the entire coercion.
    isReflexiveCo :: Coercion -> Bool
    isReflexiveCo :: Coercion -> Bool
    isReflexiveCo = Maybe (Type, Role) -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe (Type, Role) -> Bool)
    -> (Coercion -> Maybe (Type, Role)) -> Coercion -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Coercion -> Maybe (Type, Role)
    isReflexiveCo_maybe

    -- | Extracts the coerced type from a reflexive coercion. This potentially
    -- walks over the entire coercion, so avoid doing this in a loop.
    isReflexiveCo_maybe :: Coercion -> Maybe (Type, Role)
    isReflexiveCo_maybe :: Coercion -> Maybe (Type, Role)
    isReflexiveCo_maybe (Refl Type
    ty) = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty, Role
    Nominal)
    isReflexiveCo_maybe (GRefl Role
    r Type
    ty MCoercion
    mco) | MCoercion -> Bool
    isGReflMCo MCoercion
    mco = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty, Role
    r)
    isReflexiveCo_maybe Coercion
    co
      | Type
    ty1 Type -> Type -> Bool
    `eqType` Type
    ty2
      = (Type, Role) -> Maybe (Type, Role)
    forall a. a -> Maybe a
    Just (Type
    ty1, Role
    r)
      | Bool
    otherwise
      = Maybe (Type, Role)
    forall a. Maybe a
    Nothing
      where (Pair Type
    ty1 Type
    ty2, Role
    r) = Coercion -> (Pair Type, Role)
    coercionKindRole Coercion
    co

    {-
    %************************************************************************
    %*                                                                      *
                Building coercions
    %*                                                                      *
    %************************************************************************

    These "smart constructors" maintain the invariants listed in the definition
    of Coercion, and they perform very basic optimizations.

    Note [Role twiddling functions]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    There are a plethora of functions for twiddling roles:

    mkSubCo: Requires a nominal input coercion and always produces a
    representational output. This is used when you (the programmer) are sure you
    know exactly that role you have and what you want.

    downgradeRole_maybe: This function takes both the input role and the output role
    as parameters. (The *output* role comes first!) It can only *downgrade* a
    role -- that is, change it from N to R or P, or from R to P. This one-way
    behavior is why there is the "_maybe". If an upgrade is requested, this
    function produces Nothing. This is used when you need to change the role of a
    coercion, but you're not sure (as you're writing the code) of which roles are
    involved.

    This function could have been written using coercionRole to ascertain the role
    of the input. But, that function is recursive, and the caller of downgradeRole_maybe
    often knows the input role. So, this is more efficient.

    downgradeRole: This is just like downgradeRole_maybe, but it panics if the
    conversion isn't a downgrade.

    setNominalRole_maybe: This is the only function that can *upgrade* a coercion.
    The result (if it exists) is always Nominal. The input can be at any role. It
    works on a "best effort" basis, as it should never be strictly necessary to
    upgrade a coercion during compilation. It is currently only used within GHC in
    splitAppCo_maybe. In order to be a proper inverse of mkAppCo, the second
    coercion that splitAppCo_maybe returns must be nominal. But, it's conceivable
    that splitAppCo_maybe is operating over a TyConAppCo that uses a
    representational coercion. Hence the need for setNominalRole_maybe.
    splitAppCo_maybe, in turn, is used only within coercion optimization -- thus,
    it is not absolutely critical that setNominalRole_maybe be complete.

    Note that setNominalRole_maybe will never upgrade a phantom UnivCo. Phantom
    UnivCos are perfectly type-safe, whereas representational and nominal ones are
    not. (Nominal ones are no worse than representational ones, so this function *will*
    change a UnivCo Representational to a UnivCo Nominal.)

    Conal Elliott also came across a need for this function while working with the
    GHC API, as he was decomposing Core casts. The Core casts use representational
    coercions, as they must, but his use case required nominal coercions (he was
    building a GADT). So, that's why this function is exported from this module.

    One might ask: shouldn't downgradeRole_maybe just use setNominalRole_maybe as
    appropriate? I (Richard E.) have decided not to do this, because upgrading a
    role is bizarre and a caller should have to ask for this behavior explicitly.

    -}

    -- | Make a reflexive coercion
    mkReflCo :: Role -> Type -> Coercion
    mkReflCo :: Role -> Type -> Coercion
    mkReflCo Role
    Nominal Type
    ty = Type -> Coercion
    Refl Type
    ty
    mkReflCo Role
    r       Type
    ty = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty MCoercion
    MRefl

    -- | Make a representational reflexive coercion
    mkRepReflCo :: Type -> Coercion
    mkRepReflCo :: Type -> Coercion
    mkRepReflCo Type
    ty = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    Representational Type
    ty MCoercion
    MRefl

    -- | Make a nominal reflexive coercion
    mkNomReflCo :: Type -> Coercion
    mkNomReflCo :: Type -> Coercion
    mkNomReflCo = Type -> Coercion
    Refl

    -- | Apply a type constructor to a list of coercions. It is the
    -- caller's responsibility to get the roles correct on argument coercions.
    mkTyConAppCo :: HasDebugCallStack => Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo :: (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    r TyCon
    tc [Coercion]
    cos
      | Just Coercion
    co <- (() :: Constraint) => Role -> TyCon -> [Coercion] -> Maybe Coercion
    Role -> TyCon -> [Coercion] -> Maybe Coercion
    tyConAppFunCo_maybe Role
    r TyCon
    tc [Coercion]
    cos
      = Coercion
    co

      -- Expand type synonyms
      | ExpandsSyn [(CoVar, Coercion)]
    tv_co_prs Type
    rhs_ty [Coercion]
    leftover_cos <- TyCon -> [Coercion] -> ExpandSynResult Coercion
    forall tyco. TyCon -> [tyco] -> ExpandSynResult tyco
    expandSynTyCon_maybe TyCon
    tc [Coercion]
    cos
      = Coercion -> [Coercion] -> Coercion
    mkAppCos ((() :: Constraint) => Role -> LiftingContext -> Type -> Coercion
    Role -> LiftingContext -> Type -> Coercion
    liftCoSubst Role
    r ([(CoVar, Coercion)] -> LiftingContext
    mkLiftingContext [(CoVar, Coercion)]
    tv_co_prs) Type
    rhs_ty) [Coercion]
    leftover_cos

      | Just [(Type, Role)]
    tys_roles <- (Coercion -> Maybe (Type, Role))
    -> [Coercion] -> Maybe [(Type, Role)]
    forall (t :: * -> *) (f :: * -> *) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> [a] -> f [b]
    traverse Coercion -> Maybe (Type, Role)
    isReflCo_maybe [Coercion]
    cos
      = Role -> Type -> Coercion
    mkReflCo Role
    r (TyCon -> [Type] -> Type
    mkTyConApp TyCon
    tc (((Type, Role) -> Type) -> [(Type, Role)] -> [Type]
    forall a b. (a -> b) -> [a] -> [b]
    map (Type, Role) -> Type
    forall a b. (a, b) -> a
    fst [(Type, Role)]
    tys_roles))
      -- See Note [Refl invariant]

      | Bool
    otherwise = Role -> TyCon -> [Coercion] -> Coercion
    TyConAppCo Role
    r TyCon
    tc [Coercion]
    cos

    mkFunCoNoFTF :: HasDebugCallStack => Role -> CoercionN -> Coercion -> Coercion -> Coercion
    -- This version of mkFunCo takes no FunTyFlags; it works them out
    mkFunCoNoFTF :: (() :: Constraint) =>
    Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkFunCoNoFTF Role
    r Coercion
    w Coercion
    arg_co Coercion
    res_co
      = (() :: Constraint) =>
    Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    mkFunCo2 Role
    r FunTyFlag
    afl FunTyFlag
    afr Coercion
    w Coercion
    arg_co Coercion
    res_co
      where
        afl :: FunTyFlag
    afl = (() :: Constraint) => Type -> Type -> FunTyFlag
    Type -> Type -> FunTyFlag
    chooseFunTyFlag Type
    argl_ty Type
    resl_ty
        afr :: FunTyFlag
    afr = (() :: Constraint) => Type -> Type -> FunTyFlag
    Type -> Type -> FunTyFlag
    chooseFunTyFlag Type
    argr_ty Type
    resr_ty
        Pair Type
    argl_ty Type
    argr_ty = Coercion -> Pair Type
    coercionKind Coercion
    arg_co
        Pair Type
    resl_ty Type
    resr_ty = Coercion -> Pair Type
    coercionKind Coercion
    res_co

    -- | Build a function 'Coercion' from two other 'Coercion's. That is,
    -- given @co1 :: a ~ b@ and @co2 :: x ~ y@ produce @co :: (a -> x) ~ (b -> y)@
    -- or @(a => x) ~ (b => y)@, depending on the kind of @a@/@b@.
    -- This (most common) version takes a single FunTyFlag, which is used
    --   for both fco_afl and ftf_afr of the FunCo
    mkFunCo1 :: HasDebugCallStack => Role -> FunTyFlag -> CoercionN -> Coercion -> Coercion -> Coercion
    mkFunCo1 :: (() :: Constraint) =>
    Role -> FunTyFlag -> Coercion -> Coercion -> Coercion -> Coercion
    mkFunCo1 Role
    r FunTyFlag
    af Coercion
    w Coercion
    arg_co Coercion
    res_co
      = (() :: Constraint) =>
    Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    mkFunCo2 Role
    r FunTyFlag
    af FunTyFlag
    af Coercion
    w Coercion
    arg_co Coercion
    res_co

    mkNakedFunCo1 :: Role -> FunTyFlag -> CoercionN -> Coercion -> Coercion -> Coercion
    -- This version of mkFunCo1 does not check FunCo invariants (checkFunCo)
    -- It is called during typechecking on un-zonked types;
    -- in particular there may be un-zonked coercion variables.
    mkNakedFunCo1 :: Role -> FunTyFlag -> Coercion -> Coercion -> Coercion -> Coercion
    mkNakedFunCo1 Role
    r FunTyFlag
    af Coercion
    w Coercion
    arg_co Coercion
    res_co
      = Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    mkNakedFunCo2 Role
    r FunTyFlag
    af FunTyFlag
    af Coercion
    w Coercion
    arg_co Coercion
    res_co

    mkFunCo2 :: HasDebugCallStack => Role -> FunTyFlag -> FunTyFlag
                                  -> CoercionN -> Coercion -> Coercion -> Coercion
    -- This is the smart constructor for FunCo; it checks invariants
    mkFunCo2 :: (() :: Constraint) =>
    Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    mkFunCo2 Role
    r FunTyFlag
    afl FunTyFlag
    afr Coercion
    w Coercion
    arg_co Coercion
    res_co
      = Maybe SDoc -> Coercion -> Coercion
    forall a. HasCallStack => Maybe SDoc -> a -> a
    assertPprMaybe (Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Maybe SDoc
    checkFunCo Role
    r FunTyFlag
    afl FunTyFlag
    afr Coercion
    w Coercion
    arg_co Coercion
    res_co) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
        Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    mkNakedFunCo2 Role
    r FunTyFlag
    afl FunTyFlag
    afr Coercion
    w Coercion
    arg_co Coercion
    res_co

    mkNakedFunCo2 :: Role -> FunTyFlag -> FunTyFlag
                  -> CoercionN -> Coercion -> Coercion -> Coercion
    -- This is the smart constructor for FunCo
    -- "Naked"; it does not check invariants
    mkNakedFunCo2 :: Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Coercion
    mkNakedFunCo2 Role
    r FunTyFlag
    afl FunTyFlag
    afr Coercion
    w Coercion
    arg_co Coercion
    res_co
      | Just (Type
    ty1, Role
    _) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    arg_co
      , Just (Type
    ty2, Role
    _) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    res_co
      , Just (Type
    w, Role
    _)   <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    w
      = Role -> Type -> Coercion
    mkReflCo Role
    r ((() :: Constraint) => FunTyFlag -> Type -> Type -> Type -> Type
    FunTyFlag -> Type -> Type -> Type -> Type
    mkFunTy FunTyFlag
    afl Type
    w Type
    ty1 Type
    ty2)  -- See Note [Refl invariant]

      | Bool
    otherwise
      = FunCo { fco_role :: Role
    fco_role = Role
    r, fco_afl :: FunTyFlag
    fco_afl = FunTyFlag
    afl, fco_afr :: FunTyFlag
    fco_afr = FunTyFlag
    afr
              , fco_mult :: Coercion
    fco_mult = Coercion
    w, fco_arg :: Coercion
    fco_arg = Coercion
    arg_co, fco_res :: Coercion
    fco_res = Coercion
    res_co }

    checkFunCo :: Role -> FunTyFlag -> FunTyFlag
               -> CoercionN -> Coercion -> Coercion
               -> Maybe SDoc
    -- Checks well-formed-ness for FunCo
    -- Used only in assertions and Lint
    {-# NOINLINE checkFunCo #-}
    checkFunCo :: Role
    -> FunTyFlag
    -> FunTyFlag
    -> Coercion
    -> Coercion
    -> Coercion
    -> Maybe SDoc
    checkFunCo Role
    _r FunTyFlag
    afl FunTyFlag
    afr Coercion
    _w Coercion
    arg_co Coercion
    res_co
      | Bool -> Bool
    not (Type -> Bool
    ok Type
    argl_ty Bool -> Bool -> Bool
    && Type -> Bool
    ok Type
    argr_ty Bool -> Bool -> Bool
    && Type -> Bool
    ok Type
    resl_ty Bool -> Bool -> Bool
    && Type -> Bool
    ok Type
    resr_ty)
      = SDoc -> Maybe SDoc
    forall a. a -> Maybe a
    Just (SDoc -> Arity -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Bad arg or res types") Arity
    2 SDoc
    pp_inputs)

      | FunTyFlag
    afl FunTyFlag -> FunTyFlag -> Bool
    forall a. Eq a => a -> a -> Bool
    == FunTyFlag
    computed_afl
      , FunTyFlag
    afr FunTyFlag -> FunTyFlag -> Bool
    forall a. Eq a => a -> a -> Bool
    == FunTyFlag
    computed_afr
      = Maybe SDoc
    forall a. Maybe a
    Nothing
      | Bool
    otherwise
      = SDoc -> Maybe SDoc
    forall a. a -> Maybe a
    Just ([SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "afl (provided,computed):" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> FunTyFlag -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr FunTyFlag
    afl SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> FunTyFlag -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr FunTyFlag
    computed_afl
                   , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "afr (provided,computed):" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> FunTyFlag -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr FunTyFlag
    afr SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> FunTyFlag -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr FunTyFlag
    computed_afr
                   , SDoc
    pp_inputs ])
      where
        computed_afl :: FunTyFlag
    computed_afl = (() :: Constraint) => Type -> Type -> FunTyFlag
    Type -> Type -> FunTyFlag
    chooseFunTyFlag Type
    argl_ty Type
    resl_ty
        computed_afr :: FunTyFlag
    computed_afr = (() :: Constraint) => Type -> Type -> FunTyFlag
    Type -> Type -> FunTyFlag
    chooseFunTyFlag Type
    argr_ty Type
    resr_ty
        Pair Type
    argl_ty Type
    argr_ty = Coercion -> Pair Type
    coercionKind Coercion
    arg_co
        Pair Type
    resl_ty Type
    resr_ty = Coercion -> Pair Type
    coercionKind Coercion
    res_co

        pp_inputs :: SDoc
    pp_inputs = [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ String -> Type -> SDoc
    pp_ty String
    "argl" Type
    argl_ty, String -> Type -> SDoc
    pp_ty String
    "argr" Type
    argr_ty
                         , String -> Type -> SDoc
    pp_ty String
    "resl" Type
    resl_ty, String -> Type -> SDoc
    pp_ty String
    "resr" Type
    resr_ty
                         , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "arg_co:" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    arg_co
                         , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "res_co:" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    res_co ]

        ok :: Type -> Bool
    ok Type
    ty = Type -> Bool
    isTYPEorCONSTRAINT ((() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty)
        pp_ty :: String -> Type -> SDoc
    pp_ty String
    str Type
    ty = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    str SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> SDoc
    forall doc. IsLine doc => doc
    colon SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SDoc -> Arity -> SDoc -> SDoc
    hang (Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty)
                                                Arity
    2 (SDoc
    dcolon SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr ((() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty))

    -- | Apply a 'Coercion' to another 'Coercion'.
    -- The second coercion must be Nominal, unless the first is Phantom.
    -- If the first is Phantom, then the second can be either Phantom or Nominal.
    mkAppCo :: Coercion     -- ^ :: t1 ~r t2
            -> Coercion     -- ^ :: s1 ~N s2, where s1 :: k1, s2 :: k2
            -> Coercion     -- ^ :: t1 s1 ~r t2 s2
    mkAppCo :: Coercion -> Coercion -> Coercion
    mkAppCo Coercion
    co Coercion
    arg
      | Just (Type
    ty1, Role
    r) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      , Just (Type
    ty2, Role
    _) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    arg
      = Role -> Type -> Coercion
    mkReflCo Role
    r (Type -> Type -> Type
    mkAppTy Type
    ty1 Type
    ty2)

      | Just (Type
    ty1, Role
    r) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      , Just (TyCon
    tc, [Type]
    tys) <- (() :: Constraint) => Type -> Maybe (TyCon, [Type])
    Type -> Maybe (TyCon, [Type])
    splitTyConApp_maybe Type
    ty1
        -- Expand type synonyms; a TyConAppCo can't have a type synonym (#9102)
      = (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    r TyCon
    tc (Infinite Role -> [Type] -> [Coercion]
    zip_roles (Role -> TyCon -> Infinite Role
    tyConRolesX Role
    r TyCon
    tc) [Type]
    tys)
      where
        zip_roles :: Infinite Role -> [Type] -> [Coercion]
    zip_roles (Inf Role
    r1 Infinite Role
    _)  []            = [Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    r1 Role
    Nominal Coercion
    arg]
        zip_roles (Inf Role
    r1 Infinite Role
    rs) (Type
    ty1:[Type]
    tys)     = Role -> Type -> Coercion
    mkReflCo Role
    r1 Type
    ty1 Coercion -> [Coercion] -> [Coercion]
    forall a. a -> [a] -> [a]
    : Infinite Role -> [Type] -> [Coercion]
    zip_roles Infinite Role
    rs [Type]
    tys

    mkAppCo (TyConAppCo Role
    r TyCon
    tc [Coercion]
    args) Coercion
    arg
      = case Role
    r of
          Role
    Nominal          -> (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    Nominal TyCon
    tc ([Coercion]
    args [Coercion] -> [Coercion] -> [Coercion]
    forall a. [a] -> [a] -> [a]
    ++ [Coercion
    arg])
          Role
    Representational -> (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    Representational TyCon
    tc ([Coercion]
    args [Coercion] -> [Coercion] -> [Coercion]
    forall a. [a] -> [a] -> [a]
    ++ [Coercion
    arg'])
            where new_role :: Role
    new_role = TyCon -> Infinite Role
    tyConRolesRepresentational TyCon
    tc Infinite Role -> Arity -> Role
    forall a. Infinite a -> Arity -> a
    Inf.!! [Coercion] -> Arity
    forall a. [a] -> Arity
    forall (t :: * -> *) a. Foldable t => t a -> Arity
    length [Coercion]
    args
                  arg' :: Coercion
    arg'     = Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    new_role Role
    Nominal Coercion
    arg
          Role
    Phantom          -> (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    Phantom TyCon
    tc ([Coercion]
    args [Coercion] -> [Coercion] -> [Coercion]
    forall a. [a] -> [a] -> [a]
    ++ [Coercion -> Coercion
    toPhantomCo Coercion
    arg])
    mkAppCo Coercion
    co Coercion
    arg = Coercion -> Coercion -> Coercion
    AppCo Coercion
    co  Coercion
    arg
    -- Note, mkAppCo is careful to maintain invariants regarding
    -- where Refl constructors appear; see the comments in the definition
    -- of Coercion and the Note [Refl invariant] in GHC.Core.TyCo.Rep.

    -- | Applies multiple 'Coercion's to another 'Coercion', from left to right.
    -- See also 'mkAppCo'.
    mkAppCos :: Coercion
             -> [Coercion]
             -> Coercion
    mkAppCos :: Coercion -> [Coercion] -> Coercion
    mkAppCos Coercion
    co1 [Coercion]
    cos = (Coercion -> Coercion -> Coercion)
    -> Coercion -> [Coercion] -> Coercion
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' Coercion -> Coercion -> Coercion
    mkAppCo Coercion
    co1 [Coercion]
    cos

    {- Note [Unused coercion variable in ForAllCo]
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    See Note [Unused coercion variable in ForAllTy] in GHC.Core.TyCo.Rep for the
    motivation for checking coercion variable in types.
    To lift the design choice to (ForAllCo cv kind_co body_co), we have two options:

    (1) In mkForAllCo, we check whether cv is a coercion variable
        and whether it is not used in body_co. If so we construct a FunCo.
    (2) We don't do this check in mkForAllCo.
        In coercionKind, we use mkTyCoForAllTy to perform the check and construct
        a FunTy when necessary.

    We chose (2) for two reasons:

    * for a coercion, all that matters is its kind, So ForAllCo or FunCo does not
      make a difference.
    * even if cv occurs in body_co, it is possible that cv does not occur in the kind
      of body_co. Therefore the check in coercionKind is inevitable.

    The last wrinkle is that there are restrictions around the use of the cv in the
    coercion, as described in Section 5.8.5.2 of Richard's thesis. The idea is that
    we cannot prove that the type system is consistent with unrestricted use of this
    cv; the consistency proof uses an untyped rewrite relation that works over types
    with all coercions and casts removed. So, we can allow the cv to appear only in
    positions that are erased. As an approximation of this (and keeping close to the
    published theory), we currently allow the cv only within the type in a Refl node
    and under a GRefl node (including in the Coercion stored in a GRefl). It's
    possible other places are OK, too, but this is a safe approximation.

    Sadly, with heterogeneous equality, this restriction might be able to be violated;
    Richard's thesis is unable to prove that it isn't. Specifically, the liftCoSubst
    function might create an invalid coercion. Because a violation of the
    restriction might lead to a program that "goes wrong", it is checked all the time,
    even in a production compiler and without -dcore-lint. We *have* proved that the
    problem does not occur with homogeneous equality, so this check can be dropped
    once ~# is made to be homogeneous.
    -}

    -- | Make a Coercion from a tycovar, a kind coercion, and a body coercion.
    -- The kind of the tycovar should be the left-hand kind of the kind coercion.
    -- See Note [Unused coercion variable in ForAllCo]
    mkForAllCo :: TyCoVar -> CoercionN -> Coercion -> Coercion
    mkForAllCo :: CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo CoVar
    v Coercion
    kind_co Coercion
    co
      | Bool -> Bool -> Bool
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Type
    varType CoVar
    v Type -> Type -> Bool
    `eqType` (Coercion -> Type
    coercionLKind Coercion
    kind_co)) Bool
    True
      , Bool -> Bool -> Bool
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isTyVar CoVar
    v Bool -> Bool -> Bool
    || CoVar -> Coercion -> Bool
    almostDevoidCoVarOfCo CoVar
    v Coercion
    co) Bool
    True
      , Just (Type
    ty, Role
    r) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      , Coercion -> Bool
    isGReflCo Coercion
    kind_co
      = Role -> Type -> Coercion
    mkReflCo Role
    r (CoVar -> Type -> Type
    mkTyCoInvForAllTy CoVar
    v Type
    ty)
      | Bool
    otherwise
      = CoVar -> Coercion -> Coercion -> Coercion
    ForAllCo CoVar
    v Coercion
    kind_co Coercion
    co

    -- | Like 'mkForAllCo', but the inner coercion shouldn't be an obvious
    -- reflexive coercion. For example, it is guaranteed in 'mkForAllCos'.
    -- The kind of the tycovar should be the left-hand kind of the kind coercion.
    mkForAllCo_NoRefl :: TyCoVar -> CoercionN -> Coercion -> Coercion
    mkForAllCo_NoRefl :: CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo_NoRefl CoVar
    v Coercion
    kind_co Coercion
    co
      | Bool -> Bool -> Bool
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Type
    varType CoVar
    v Type -> Type -> Bool
    `eqType` (Coercion -> Type
    coercionLKind Coercion
    kind_co)) Bool
    True
      , Bool -> Bool -> Bool
    forall a. HasCallStack => Bool -> a -> a
    assert (Bool -> Bool
    not (Coercion -> Bool
    isReflCo Coercion
    co)) Bool
    True
      , CoVar -> Bool
    isCoVar CoVar
    v
      , Bool -> Bool -> Bool
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Coercion -> Bool
    almostDevoidCoVarOfCo CoVar
    v Coercion
    co) Bool
    True
      , Bool -> Bool
    not (CoVar
    v CoVar -> VarSet -> Bool
    `elemVarSet` Coercion -> VarSet
    tyCoVarsOfCo Coercion
    co)
      = (() :: Constraint) =>
    Role -> Coercion -> Coercion -> Coercion -> Coercion
    Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkFunCoNoFTF (Coercion -> Role
    coercionRole Coercion
    co) (Type -> Coercion
    multToCo Type
    ManyTy) Coercion
    kind_co Coercion
    co
          -- Functions from coercions are always unrestricted
      | Bool
    otherwise
      = CoVar -> Coercion -> Coercion -> Coercion
    ForAllCo CoVar
    v Coercion
    kind_co Coercion
    co

    -- | Make nested ForAllCos
    mkForAllCos :: [(TyCoVar, CoercionN)] -> Coercion -> Coercion
    mkForAllCos :: [(CoVar, Coercion)] -> Coercion -> Coercion
    mkForAllCos [(CoVar, Coercion)]
    bndrs Coercion
    co
      | Just (Type
    ty, Role
    r ) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      = let ([(CoVar, Coercion)]
    refls_rev'd, [(CoVar, Coercion)]
    non_refls_rev'd) = ((CoVar, Coercion) -> Bool)
    -> [(CoVar, Coercion)]
    -> ([(CoVar, Coercion)], [(CoVar, Coercion)])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    span (Coercion -> Bool
    isReflCo (Coercion -> Bool)
    -> ((CoVar, Coercion) -> Coercion) -> (CoVar, Coercion) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (CoVar, Coercion) -> Coercion
    forall a b. (a, b) -> b
    snd) ([(CoVar, Coercion)] -> [(CoVar, Coercion)]
    forall a. [a] -> [a]
    reverse [(CoVar, Coercion)]
    bndrs) in
        (Coercion -> (CoVar, Coercion) -> Coercion)
    -> Coercion -> [(CoVar, Coercion)] -> Coercion
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (((CoVar, Coercion) -> Coercion -> Coercion)
    -> Coercion -> (CoVar, Coercion) -> Coercion
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (((CoVar, Coercion) -> Coercion -> Coercion)
     -> Coercion -> (CoVar, Coercion) -> Coercion)
    -> ((CoVar, Coercion) -> Coercion -> Coercion)
    -> Coercion
    -> (CoVar, Coercion)
    -> Coercion
    forall a b. (a -> b) -> a -> b
    $ (CoVar -> Coercion -> Coercion -> Coercion)
    -> (CoVar, Coercion) -> Coercion -> Coercion
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo_NoRefl)
               (Role -> Type -> Coercion
    mkReflCo Role
    r ([CoVar] -> Type -> Type
    mkTyCoInvForAllTys ([CoVar] -> [CoVar]
    forall a. [a] -> [a]
    reverse (((CoVar, Coercion) -> CoVar) -> [(CoVar, Coercion)] -> [CoVar]
    forall a b. (a -> b) -> [a] -> [b]
    map (CoVar, Coercion) -> CoVar
    forall a b. (a, b) -> a
    fst [(CoVar, Coercion)]
    refls_rev'd)) Type
    ty))
               [(CoVar, Coercion)]
    non_refls_rev'd
      | Bool
    otherwise
      = ((CoVar, Coercion) -> Coercion -> Coercion)
    -> Coercion -> [(CoVar, Coercion)] -> Coercion
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr ((CoVar -> Coercion -> Coercion -> Coercion)
    -> (CoVar, Coercion) -> Coercion -> Coercion
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo_NoRefl) Coercion
    co [(CoVar, Coercion)]
    bndrs

    -- | Make a Coercion quantified over a type/coercion variable;
    -- the variable has the same type in both sides of the coercion
    mkHomoForAllCos :: [TyCoVar] -> Coercion -> Coercion
    mkHomoForAllCos :: [CoVar] -> Coercion -> Coercion
    mkHomoForAllCos [CoVar]
    vs Coercion
    co
      | Just (Type
    ty, Role
    r) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      = Role -> Type -> Coercion
    mkReflCo Role
    r ([CoVar] -> Type -> Type
    mkTyCoInvForAllTys [CoVar]
    vs Type
    ty)
      | Bool
    otherwise
      = [CoVar] -> Coercion -> Coercion
    mkHomoForAllCos_NoRefl [CoVar]
    vs Coercion
    co

    -- | Like 'mkHomoForAllCos', but the inner coercion shouldn't be an obvious
    -- reflexive coercion. For example, it is guaranteed in 'mkHomoForAllCos'.
    mkHomoForAllCos_NoRefl :: [TyCoVar] -> Coercion -> Coercion
    mkHomoForAllCos_NoRefl :: [CoVar] -> Coercion -> Coercion
    mkHomoForAllCos_NoRefl [CoVar]
    vs Coercion
    orig_co
      = Bool
    -> ((CoVar -> Coercion -> Coercion)
        -> Coercion -> [CoVar] -> Coercion)
    -> (CoVar -> Coercion -> Coercion)
    -> Coercion
    -> [CoVar]
    -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Bool -> Bool
    not (Coercion -> Bool
    isReflCo Coercion
    orig_co))
        (CoVar -> Coercion -> Coercion) -> Coercion -> [CoVar] -> Coercion
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr CoVar -> Coercion -> Coercion
    go Coercion
    orig_co [CoVar]
    vs
      where
        go :: CoVar -> Coercion -> Coercion
    go CoVar
    v Coercion
    co = CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo_NoRefl CoVar
    v (Type -> Coercion
    mkNomReflCo (CoVar -> Type
    varType CoVar
    v)) Coercion
    co

    mkCoVarCo :: CoVar -> Coercion
    -- cv :: s ~# t
    -- See Note [mkCoVarCo]
    mkCoVarCo :: CoVar -> Coercion
    mkCoVarCo CoVar
    cv = CoVar -> Coercion
    CoVarCo CoVar
    cv

    mkCoVarCos :: [CoVar] -> [Coercion]
    mkCoVarCos :: [CoVar] -> [Coercion]
    mkCoVarCos = (CoVar -> Coercion) -> [CoVar] -> [Coercion]
    forall a b. (a -> b) -> [a] -> [b]
    map CoVar -> Coercion
    mkCoVarCo

    {- Note [mkCoVarCo]
    ~~~~~~~~~~~~~~~~~~~
    In the past, mkCoVarCo optimised (c :: t~t) to (Refl t).  That is
    valid (although see Note [Unbound RULE binders] in GHC.Core.Rules), but
    it's a relatively expensive test and perhaps better done in
    optCoercion.  Not a big deal either way.
    -}

    mkAxInstCo :: Role -> CoAxiom br -> BranchIndex -> [Type] -> [Coercion]
               -> Coercion
    -- mkAxInstCo can legitimately be called over-saturated;
    -- i.e. with more type arguments than the coercion requires
    mkAxInstCo :: forall (br :: BranchFlag).
    Role -> CoAxiom br -> Arity -> [Type] -> [Coercion] -> Coercion
    mkAxInstCo Role
    role CoAxiom br
    ax Arity
    index [Type]
    tys [Coercion]
    cos
      | Arity
    arity Arity -> Arity -> Bool
    forall a. Eq a => a -> a -> Bool
    == Arity
    n_tys = Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    role Role
    ax_role (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                         CoAxiom Branched -> Arity -> [Coercion] -> Coercion
    mkAxiomInstCo CoAxiom Branched
    ax_br Arity
    index ([Coercion]
    rtys [Coercion] -> [Coercion] -> [Coercion]
    forall a. [a] -> [a] -> [a]
    `chkAppend` [Coercion]
    cos)
      | Bool
    otherwise      = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Arity
    arity Arity -> Arity -> Bool
    forall a. Ord a => a -> a -> Bool
    < Arity
    n_tys) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                         Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    role Role
    ax_role (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                         Coercion -> [Coercion] -> Coercion
    mkAppCos (CoAxiom Branched -> Arity -> [Coercion] -> Coercion
    mkAxiomInstCo CoAxiom Branched
    ax_br Arity
    index
                                                 ([Coercion]
    ax_args [Coercion] -> [Coercion] -> [Coercion]
    forall a. [a] -> [a] -> [a]
    `chkAppend` [Coercion]
    cos))
                                  [Coercion]
    leftover_args
      where
        n_tys :: Arity
    n_tys         = [Type] -> Arity
    forall a. [a] -> Arity
    forall (t :: * -> *) a. Foldable t => t a -> Arity
    length [Type]
    tys
        ax_br :: CoAxiom Branched
    ax_br         = CoAxiom br -> CoAxiom Branched
    forall (br :: BranchFlag). CoAxiom br -> CoAxiom Branched
    toBranchedAxiom CoAxiom br
    ax
        branch :: CoAxBranch
    branch        = CoAxiom Branched -> Arity -> CoAxBranch
    forall (br :: BranchFlag). CoAxiom br -> Arity -> CoAxBranch
    coAxiomNthBranch CoAxiom Branched
    ax_br Arity
    index
        tvs :: [CoVar]
    tvs           = CoAxBranch -> [CoVar]
    coAxBranchTyVars CoAxBranch
    branch
        arity :: Arity
    arity         = [CoVar] -> Arity
    forall a. [a] -> Arity
    forall (t :: * -> *) a. Foldable t => t a -> Arity
    length [CoVar]
    tvs
        arg_roles :: [Role]
    arg_roles     = CoAxBranch -> [Role]
    coAxBranchRoles CoAxBranch
    branch
        rtys :: [Coercion]
    rtys          = (Role -> Type -> Coercion) -> [Role] -> [Type] -> [Coercion]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Role -> Type -> Coercion
    mkReflCo ([Role]
    arg_roles [Role] -> [Role] -> [Role]
    forall a. [a] -> [a] -> [a]
    ++ Role -> [Role]
    forall a. a -> [a]
    repeat Role
    Nominal) [Type]
    tys
        ([Coercion]
    ax_args, [Coercion]
    leftover_args)
                      = Arity -> [Coercion] -> ([Coercion], [Coercion])
    forall a. Arity -> [a] -> ([a], [a])
    splitAt Arity
    arity [Coercion]
    rtys
        ax_role :: Role
    ax_role       = CoAxiom br -> Role
    forall (br :: BranchFlag). CoAxiom br -> Role
    coAxiomRole CoAxiom br
    ax

    -- worker function
    mkAxiomInstCo :: CoAxiom Branched -> BranchIndex -> [Coercion] -> Coercion
    mkAxiomInstCo :: CoAxiom Branched -> Arity -> [Coercion] -> Coercion
    mkAxiomInstCo CoAxiom Branched
    ax Arity
    index [Coercion]
    args
      = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert ([Coercion]
    args [Coercion] -> Arity -> Bool
    forall a. [a] -> Arity -> Bool
    `lengthIs` CoAxiom Branched -> Arity -> Arity
    forall (br :: BranchFlag). CoAxiom br -> Arity -> Arity
    coAxiomArity CoAxiom Branched
    ax Arity
    index) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
        CoAxiom Branched -> Arity -> [Coercion] -> Coercion
    AxiomInstCo CoAxiom Branched
    ax Arity
    index [Coercion]
    args

    -- to be used only with unbranched axioms
    mkUnbranchedAxInstCo :: Role -> CoAxiom Unbranched
                         -> [Type] -> [Coercion] -> Coercion
    mkUnbranchedAxInstCo :: Role -> CoAxiom Unbranched -> [Type] -> [Coercion] -> Coercion
    mkUnbranchedAxInstCo Role
    role CoAxiom Unbranched
    ax [Type]
    tys [Coercion]
    cos
      = Role
    -> CoAxiom Unbranched -> Arity -> [Type] -> [Coercion] -> Coercion
    forall (br :: BranchFlag).
    Role -> CoAxiom br -> Arity -> [Type] -> [Coercion] -> Coercion
    mkAxInstCo Role
    role CoAxiom Unbranched
    ax Arity
    0 [Type]
    tys [Coercion]
    cos

    mkAxInstRHS :: CoAxiom br -> BranchIndex -> [Type] -> [Coercion] -> Type
    -- Instantiate the axiom with specified types,
    -- returning the instantiated RHS
    -- A companion to mkAxInstCo:
    --    mkAxInstRhs ax index tys = snd (coercionKind (mkAxInstCo ax index tys))
    mkAxInstRHS :: forall (br :: BranchFlag).
    CoAxiom br -> Arity -> [Type] -> [Coercion] -> Type
    mkAxInstRHS CoAxiom br
    ax Arity
    index [Type]
    tys [Coercion]
    cos
      = Bool -> Type -> Type
    forall a. HasCallStack => Bool -> a -> a
    assert ([CoVar]
    tvs [CoVar] -> [Type] -> Bool
    forall a b. [a] -> [b] -> Bool
    `equalLength` [Type]
    tys1) (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
        Type -> [Type] -> Type
    mkAppTys Type
    rhs' [Type]
    tys2
      where
        branch :: CoAxBranch
    branch       = CoAxiom br -> Arity -> CoAxBranch
    forall (br :: BranchFlag). CoAxiom br -> Arity -> CoAxBranch
    coAxiomNthBranch CoAxiom br
    ax Arity
    index
        tvs :: [CoVar]
    tvs          = CoAxBranch -> [CoVar]
    coAxBranchTyVars CoAxBranch
    branch
        cvs :: [CoVar]
    cvs          = CoAxBranch -> [CoVar]
    coAxBranchCoVars CoAxBranch
    branch
        ([Type]
    tys1, [Type]
    tys2) = [CoVar] -> [Type] -> ([Type], [Type])
    forall b a. [b] -> [a] -> ([a], [a])
    splitAtList [CoVar]
    tvs [Type]
    tys
        rhs' :: Type
    rhs'         = [CoVar] -> [Type] -> Type -> Type
    (() :: Constraint) => [CoVar] -> [Type] -> Type -> Type
    substTyWith [CoVar]
    tvs [Type]
    tys1 (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
                       [CoVar] -> [Coercion] -> Type -> Type
    substTyWithCoVars [CoVar]
    cvs [Coercion]
    cos (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
                       CoAxBranch -> Type
    coAxBranchRHS CoAxBranch
    branch

    mkUnbranchedAxInstRHS :: CoAxiom Unbranched -> [Type] -> [Coercion] -> Type
    mkUnbranchedAxInstRHS :: CoAxiom Unbranched -> [Type] -> [Coercion] -> Type
    mkUnbranchedAxInstRHS CoAxiom Unbranched
    ax = CoAxiom Unbranched -> Arity -> [Type] -> [Coercion] -> Type
    forall (br :: BranchFlag).
    CoAxiom br -> Arity -> [Type] -> [Coercion] -> Type
    mkAxInstRHS CoAxiom Unbranched
    ax Arity
    0

    -- | Return the left-hand type of the axiom, when the axiom is instantiated
    -- at the types given.
    mkAxInstLHS :: CoAxiom br -> BranchIndex -> [Type] -> [Coercion] -> Type
    mkAxInstLHS :: forall (br :: BranchFlag).
    CoAxiom br -> Arity -> [Type] -> [Coercion] -> Type
    mkAxInstLHS CoAxiom br
    ax Arity
    index [Type]
    tys [Coercion]
    cos
      = Bool -> Type -> Type
    forall a. HasCallStack => Bool -> a -> a
    assert ([CoVar]
    tvs [CoVar] -> [Type] -> Bool
    forall a b. [a] -> [b] -> Bool
    `equalLength` [Type]
    tys1) (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
        TyCon -> [Type] -> Type
    mkTyConApp TyCon
    fam_tc ([Type]
    lhs_tys [Type] -> [Type] -> [Type]
    forall a. [a] -> [a] -> [a]
    `chkAppend` [Type]
    tys2)
      where
        branch :: CoAxBranch
    branch       = CoAxiom br -> Arity -> CoAxBranch
    forall (br :: BranchFlag). CoAxiom br -> Arity -> CoAxBranch
    coAxiomNthBranch CoAxiom br
    ax Arity
    index
        tvs :: [CoVar]
    tvs          = CoAxBranch -> [CoVar]
    coAxBranchTyVars CoAxBranch
    branch
        cvs :: [CoVar]
    cvs          = CoAxBranch -> [CoVar]
    coAxBranchCoVars CoAxBranch
    branch
        ([Type]
    tys1, [Type]
    tys2) = [CoVar] -> [Type] -> ([Type], [Type])
    forall b a. [b] -> [a] -> ([a], [a])
    splitAtList [CoVar]
    tvs [Type]
    tys
        lhs_tys :: [Type]
    lhs_tys      = [CoVar] -> [Type] -> [Type] -> [Type]
    substTysWith [CoVar]
    tvs [Type]
    tys1 ([Type] -> [Type]) -> [Type] -> [Type]
    forall a b. (a -> b) -> a -> b
    $
                       [CoVar] -> [Coercion] -> [Type] -> [Type]
    substTysWithCoVars [CoVar]
    cvs [Coercion]
    cos ([Type] -> [Type]) -> [Type] -> [Type]
    forall a b. (a -> b) -> a -> b
    $
                       CoAxBranch -> [Type]
    coAxBranchLHS CoAxBranch
    branch
        fam_tc :: TyCon
    fam_tc       = CoAxiom br -> TyCon
    forall (br :: BranchFlag). CoAxiom br -> TyCon
    coAxiomTyCon CoAxiom br
    ax

    -- | Instantiate the left-hand side of an unbranched axiom
    mkUnbranchedAxInstLHS :: CoAxiom Unbranched -> [Type] -> [Coercion] -> Type
    mkUnbranchedAxInstLHS :: CoAxiom Unbranched -> [Type] -> [Coercion] -> Type
    mkUnbranchedAxInstLHS CoAxiom Unbranched
    ax = CoAxiom Unbranched -> Arity -> [Type] -> [Coercion] -> Type
    forall (br :: BranchFlag).
    CoAxiom br -> Arity -> [Type] -> [Coercion] -> Type
    mkAxInstLHS CoAxiom Unbranched
    ax Arity
    0

    -- | Make a coercion from a coercion hole
    mkHoleCo :: CoercionHole -> Coercion
    mkHoleCo :: CoercionHole -> Coercion
    mkHoleCo CoercionHole
    h = CoercionHole -> Coercion
    HoleCo CoercionHole
    h

    -- | Make a universal coercion between two arbitrary types.
    mkUnivCo :: UnivCoProvenance
             -> Role       -- ^ role of the built coercion, "r"
             -> Type       -- ^ t1 :: k1
             -> Type       -- ^ t2 :: k2
             -> Coercion   -- ^ :: t1 ~r t2
    mkUnivCo :: UnivCoProvenance -> Role -> Type -> Type -> Coercion
    mkUnivCo UnivCoProvenance
    prov Role
    role Type
    ty1 Type
    ty2
      | Type
    ty1 Type -> Type -> Bool
    `eqType` Type
    ty2 = Role -> Type -> Coercion
    mkReflCo Role
    role Type
    ty1
      | Bool
    otherwise        = UnivCoProvenance -> Role -> Type -> Type -> Coercion
    UnivCo UnivCoProvenance
    prov Role
    role Type
    ty1 Type
    ty2

    -- | Create a symmetric version of the given 'Coercion' that asserts
    --   equality between the same types but in the other "direction", so
    --   a kind of @t1 ~ t2@ becomes the kind @t2 ~ t1@.
    mkSymCo :: Coercion -> Coercion

    -- Do a few simple optimizations, but don't bother pushing occurrences
    -- of symmetry to the leaves; the optimizer will take care of that.
    mkSymCo :: Coercion -> Coercion
    mkSymCo Coercion
    co | Coercion -> Bool
    isReflCo Coercion
    co          = Coercion
    co
    mkSymCo    (SymCo Coercion
    co)             = Coercion
    co
    mkSymCo    (SubCo (SymCo Coercion
    co))     = Coercion -> Coercion
    SubCo Coercion
    co
    mkSymCo Coercion
    co                        = Coercion -> Coercion
    SymCo Coercion
    co

    -- | Create a new 'Coercion' by composing the two given 'Coercion's transitively.
    --   (co1 ; co2)
    mkTransCo :: Coercion -> Coercion -> Coercion
    mkTransCo :: Coercion -> Coercion -> Coercion
    mkTransCo Coercion
    co1 Coercion
    co2 | Coercion -> Bool
    isReflCo Coercion
    co1 = Coercion
    co2
                      | Coercion -> Bool
    isReflCo Coercion
    co2 = Coercion
    co1
    mkTransCo (GRefl Role
    r Type
    t1 (MCo Coercion
    co1)) (GRefl Role
    _ Type
    _ (MCo Coercion
    co2))
      = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    t1 (Coercion -> MCoercion
    MCo (Coercion -> MCoercion) -> Coercion -> MCoercion
    forall a b. (a -> b) -> a -> b
    $ Coercion -> Coercion -> Coercion
    mkTransCo Coercion
    co1 Coercion
    co2)
    mkTransCo Coercion
    co1 Coercion
    co2                = Coercion -> Coercion -> Coercion
    TransCo Coercion
    co1 Coercion
    co2

    mkSelCo :: HasDebugCallStack
            => CoSel
            -> Coercion
            -> Coercion
    mkSelCo :: (() :: Constraint) => CoSel -> Coercion -> Coercion
    mkSelCo CoSel
    n Coercion
    co = (() :: Constraint) => CoSel -> Coercion -> Maybe Coercion
    CoSel -> Coercion -> Maybe Coercion
    mkSelCo_maybe CoSel
    n Coercion
    co Maybe Coercion -> Coercion -> Coercion
    forall a. Maybe a -> a -> a
    `orElse` CoSel -> Coercion -> Coercion
    SelCo CoSel
    n Coercion
    co

    mkSelCo_maybe :: HasDebugCallStack
            => CoSel
            -> Coercion
            -> Maybe Coercion
    -- mkSelCo_maybe tries to optimise call to mkSelCo
    mkSelCo_maybe :: (() :: Constraint) => CoSel -> Coercion -> Maybe Coercion
    mkSelCo_maybe CoSel
    cs Coercion
    co
      = Bool -> SDoc -> Maybe Coercion -> Maybe Coercion
    forall a. HasCallStack => Bool -> SDoc -> a -> a
    assertPpr (CoSel -> Bool
    good_call CoSel
    cs) SDoc
    bad_call_msg (Maybe Coercion -> Maybe Coercion)
    -> Maybe Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $
        CoSel -> Coercion -> Maybe Coercion
    go CoSel
    cs Coercion
    co
      where
        Pair Type
    ty1 Type
    ty2 = Coercion -> Pair Type
    coercionKind Coercion
    co

        go :: CoSel -> Coercion -> Maybe Coercion
    go CoSel
    cs Coercion
    co
          | Just (Type
    ty, Role
    _co_role) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
          = let new_role :: Role
    new_role = Coercion -> Role
    coercionRole (CoSel -> Coercion -> Coercion
    SelCo CoSel
    cs Coercion
    co)
            in Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Role -> Type -> Coercion
    mkReflCo Role
    new_role ((() :: Constraint) => CoSel -> Type -> Type
    CoSel -> Type -> Type
    getNthFromType CoSel
    cs Type
    ty))
            -- The role of the result (new_role) does not have to
            -- be equal to _co_role, the role of co, per Note [SelCo].
            -- This was revealed by #23938.

        go CoSel
    SelForAll (ForAllCo CoVar
    _ Coercion
    kind_co Coercion
    _)
          = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    kind_co
          -- If co :: (forall a1:k1. t1) ~ (forall a2:k2. t2)
          -- then (nth SelForAll co :: k1 ~N k2)
          -- If co :: (forall a1:t1 ~ t2. t1) ~ (forall a2:t3 ~ t4. t2)
          -- then (nth SelForAll co :: (t1 ~ t2) ~N (t3 ~ t4))

        go (SelFun FunSel
    fs) (FunCo Role
    _ FunTyFlag
    _ FunTyFlag
    _ Coercion
    w Coercion
    arg Coercion
    res)
          = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (FunSel -> Coercion -> Coercion -> Coercion -> Coercion
    forall a. FunSel -> a -> a -> a -> a
    getNthFun FunSel
    fs Coercion
    w Coercion
    arg Coercion
    res)

        go (SelTyCon Arity
    i Role
    r) (TyConAppCo Role
    r0 TyCon
    tc [Coercion]
    arg_cos)
          = Bool -> SDoc -> Maybe Coercion -> Maybe Coercion
    forall a. HasCallStack => Bool -> SDoc -> a -> a
    assertPpr (Role
    r Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role -> TyCon -> Arity -> Role
    tyConRole Role
    r0 TyCon
    tc Arity
    i)
                      ([SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ TyCon -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr TyCon
    tc, [Coercion] -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr [Coercion]
    arg_cos, Role -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Role
    r0, Arity -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Arity
    i, Role -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Role
    r ]) (Maybe Coercion -> Maybe Coercion)
    -> Maybe Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $
            Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just ([Coercion]
    arg_cos [Coercion] -> Arity -> Coercion
    forall a. Outputable a => [a] -> Arity -> a
    `getNth` Arity
    i)

        go CoSel
    cs (SymCo Coercion
    co)  -- Recurse, hoping to get to a TyConAppCo or FunCo
          = do { Coercion
    co' <- CoSel -> Coercion -> Maybe Coercion
    go CoSel
    cs Coercion
    co; Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Coercion -> Coercion
    mkSymCo Coercion
    co') }

        go CoSel
    _ Coercion
    _ = Maybe Coercion
    forall a. Maybe a
    Nothing

        -- Assertion checking
        bad_call_msg :: SDoc
    bad_call_msg = [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Coercion =" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    co
                            , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "LHS ty =" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty1
                            , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "RHS ty =" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty2
                            , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "cs =" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> CoSel -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoSel
    cs
                            , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "coercion role =" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Role -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (Coercion -> Role
    coercionRole Coercion
    co) ]

        -- good_call checks the typing rules given in Note [SelCo]
        good_call :: CoSel -> Bool
    good_call CoSel
    SelForAll
          | Just (CoVar
    _tv1, Type
    _) <- Type -> Maybe (CoVar, Type)
    splitForAllTyCoVar_maybe Type
    ty1
          , Just (CoVar
    _tv2, Type
    _) <- Type -> Maybe (CoVar, Type)
    splitForAllTyCoVar_maybe Type
    ty2
          =  Bool
    True

        good_call (SelFun {})
           = Type -> Bool
    isFunTy Type
    ty1 Bool -> Bool -> Bool
    && Type -> Bool
    isFunTy Type
    ty2

        good_call (SelTyCon Arity
    n Role
    r)
           | Just (TyCon
    tc1, [Type]
    tys1) <- (() :: Constraint) => Type -> Maybe (TyCon, [Type])
    Type -> Maybe (TyCon, [Type])
    splitTyConApp_maybe Type
    ty1
           , Just (TyCon
    tc2, [Type]
    tys2) <- (() :: Constraint) => Type -> Maybe (TyCon, [Type])
    Type -> Maybe (TyCon, [Type])
    splitTyConApp_maybe Type
    ty2
           , let { len1 :: Arity
    len1 = [Type] -> Arity
    forall a. [a] -> Arity
    forall (t :: * -> *) a. Foldable t => t a -> Arity
    length [Type]
    tys1
                 ; len2 :: Arity
    len2 = [Type] -> Arity
    forall a. [a] -> Arity
    forall (t :: * -> *) a. Foldable t => t a -> Arity
    length [Type]
    tys2 }
           =  (TyCon
    tc1 TyCon -> TyCon -> Bool
    forall a. Eq a => a -> a -> Bool
    == TyCon
    tc2 Bool -> Bool -> Bool
    || (TyCon -> Bool
    tyConIsTYPEorCONSTRAINT TyCon
    tc1 Bool -> Bool -> Bool
    && TyCon -> Bool
    tyConIsTYPEorCONSTRAINT TyCon
    tc2))
                          -- tyConIsTYPEorCONSTRAINT: see Note [mkRuntimeRepCo]
           Bool -> Bool -> Bool
    && Arity
    len1 Arity -> Arity -> Bool
    forall a. Eq a => a -> a -> Bool
    == Arity
    len2
           Bool -> Bool -> Bool
    && Arity
    n Arity -> Arity -> Bool
    forall a. Ord a => a -> a -> Bool
    < Arity
    len1
           Bool -> Bool -> Bool
    && Role
    r Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role -> TyCon -> Arity -> Role
    tyConRole (Coercion -> Role
    coercionRole Coercion
    co) TyCon
    tc1 Arity
    n

        good_call CoSel
    _ = Bool
    False

    -- | Extract the nth field of a FunCo
    getNthFun :: FunSel
              -> a    -- ^ multiplicity
              -> a    -- ^ argument
              -> a    -- ^ result
              -> a    -- ^ One of the above three
    getNthFun :: forall a. FunSel -> a -> a -> a -> a
    getNthFun FunSel
    SelMult a
    mult a
    _   a
    _   = a
    mult
    getNthFun FunSel
    SelArg a
    _     a
    arg a
    _   = a
    arg
    getNthFun FunSel
    SelRes a
    _     a
    _   a
    res = a
    res

    mkLRCo :: LeftOrRight -> Coercion -> Coercion
    mkLRCo :: LeftOrRight -> Coercion -> Coercion
    mkLRCo LeftOrRight
    lr Coercion
    co
      | Just (Type
    ty, Role
    eq) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
      = Role -> Type -> Coercion
    mkReflCo Role
    eq (LeftOrRight -> (Type, Type) -> Type
    forall a. LeftOrRight -> (a, a) -> a
    pickLR LeftOrRight
    lr (Type -> (Type, Type)
    splitAppTy Type
    ty))
      | Bool
    otherwise
      = LeftOrRight -> Coercion -> Coercion
    LRCo LeftOrRight
    lr Coercion
    co

    -- | Instantiates a 'Coercion'.
    mkInstCo :: Coercion -> CoercionN -> Coercion
    mkInstCo :: Coercion -> Coercion -> Coercion
    mkInstCo (ForAllCo CoVar
    tcv Coercion
    _kind_co Coercion
    body_co) Coercion
    co
      | Just (Type
    arg, Role
    _) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co
          -- works for both tyvar and covar
      = Subst -> Coercion -> Coercion
    substCoUnchecked ([CoVar] -> [Type] -> Subst
    (() :: Constraint) => [CoVar] -> [Type] -> Subst
    zipTCvSubst [CoVar
    tcv] [Type
    arg]) Coercion
    body_co
    mkInstCo Coercion
    co Coercion
    arg = Coercion -> Coercion -> Coercion
    InstCo Coercion
    co Coercion
    arg

    -- | Given @ty :: k1@, @co :: k1 ~ k2@,
    -- produces @co' :: ty ~r (ty |> co)@
    mkGReflRightCo :: Role -> Type -> CoercionN -> Coercion
    mkGReflRightCo :: Role -> Type -> Coercion -> Coercion
    mkGReflRightCo Role
    r Type
    ty Coercion
    co
      | Coercion -> Bool
    isGReflCo Coercion
    co = Role -> Type -> Coercion
    mkReflCo Role
    r Type
    ty
        -- the kinds of @k1@ and @k2@ are the same, thus @isGReflCo@
        -- instead of @isReflCo@
      | Bool
    otherwise = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty (Coercion -> MCoercion
    MCo Coercion
    co)

    -- | Given @r@, @ty :: k1@, and @co :: k1 ~N k2@,
    -- produces @co' :: (ty |> co) ~r ty@
    mkGReflLeftCo :: Role -> Type -> CoercionN -> Coercion
    mkGReflLeftCo :: Role -> Type -> Coercion -> Coercion
    mkGReflLeftCo Role
    r Type
    ty Coercion
    co
      | Coercion -> Bool
    isGReflCo Coercion
    co = Role -> Type -> Coercion
    mkReflCo Role
    r Type
    ty
        -- the kinds of @k1@ and @k2@ are the same, thus @isGReflCo@
        -- instead of @isReflCo@
      | Bool
    otherwise    = Coercion -> Coercion
    mkSymCo (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $ Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty (Coercion -> MCoercion
    MCo Coercion
    co)

    -- | Given @ty :: k1@, @co :: k1 ~ k2@, @co2:: ty ~r ty'@,
    -- produces @co' :: (ty |> co) ~r ty'
    -- It is not only a utility function, but it saves allocation when co
    -- is a GRefl coercion.
    mkCoherenceLeftCo :: Role -> Type -> CoercionN -> Coercion -> Coercion
    mkCoherenceLeftCo :: Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceLeftCo Role
    r Type
    ty Coercion
    co Coercion
    co2
      | Coercion -> Bool
    isGReflCo Coercion
    co = Coercion
    co2
      | Bool
    otherwise    = (Coercion -> Coercion
    mkSymCo (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $ Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty (Coercion -> MCoercion
    MCo Coercion
    co)) Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    co2

    -- | Given @ty :: k1@, @co :: k1 ~ k2@, @co2:: ty' ~r ty@,
    -- produces @co' :: ty' ~r (ty |> co)
    -- It is not only a utility function, but it saves allocation when co
    -- is a GRefl coercion.
    mkCoherenceRightCo :: Role -> Type -> CoercionN -> Coercion -> Coercion
    mkCoherenceRightCo :: Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceRightCo Role
    r Type
    ty Coercion
    co Coercion
    co2
      | Coercion -> Bool
    isGReflCo Coercion
    co = Coercion
    co2
      | Bool
    otherwise    = Coercion
    co2 Coercion -> Coercion -> Coercion
    `mkTransCo` Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r Type
    ty (Coercion -> MCoercion
    MCo Coercion
    co)

    -- | Given @co :: (a :: k) ~ (b :: k')@ produce @co' :: k ~ k'@.
    mkKindCo :: Coercion -> Coercion
    mkKindCo :: Coercion -> Coercion
    mkKindCo Coercion
    co | Just (Type
    ty, Role
    _) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    co = Type -> Coercion
    Refl ((() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty)
    mkKindCo (GRefl Role
    _ Type
    _ (MCo Coercion
    co)) = Coercion
    co
    mkKindCo (UnivCo (PhantomProv Coercion
    h) Role
    _ Type
    _ Type
    _)    = Coercion
    h
    mkKindCo (UnivCo (ProofIrrelProv Coercion
    h) Role
    _ Type
    _ Type
    _) = Coercion
    h
    mkKindCo Coercion
    co
      | Pair Type
    ty1 Type
    ty2 <- Coercion -> Pair Type
    coercionKind Coercion
    co
           -- generally, calling coercionKind during coercion creation is a bad idea,
           -- as it can lead to exponential behavior. But, we don't have nested mkKindCos,
           -- so it's OK here.
      , let tk1 :: Type
    tk1 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty1
            tk2 :: Type
    tk2 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty2
      , Type
    tk1 Type -> Type -> Bool
    `eqType` Type
    tk2
      = Type -> Coercion
    Refl Type
    tk1
      | Bool
    otherwise
      = Coercion -> Coercion
    KindCo Coercion
    co

    mkSubCo :: HasDebugCallStack => Coercion -> Coercion
    -- Input coercion is Nominal, result is Representational
    -- see also Note [Role twiddling functions]
    mkSubCo :: (() :: Constraint) => Coercion -> Coercion
    mkSubCo (Refl Type
    ty) = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    Representational Type
    ty MCoercion
    MRefl
    mkSubCo (GRefl Role
    Nominal Type
    ty MCoercion
    co) = Role -> Type -> MCoercion -> Coercion
    GRefl Role
    Representational Type
    ty MCoercion
    co
    mkSubCo (TyConAppCo Role
    Nominal TyCon
    tc [Coercion]
    cos)
      = Role -> TyCon -> [Coercion] -> Coercion
    TyConAppCo Role
    Representational TyCon
    tc (TyCon -> [Coercion] -> [Coercion]
    applyRoles TyCon
    tc [Coercion]
    cos)
    mkSubCo co :: Coercion
    co@(FunCo { fco_role :: Coercion -> Role
    fco_role = Role
    Nominal, fco_arg :: Coercion -> Coercion
    fco_arg = Coercion
    arg, fco_res :: Coercion -> Coercion
    fco_res = Coercion
    res })
      = Coercion
    co { fco_role = Representational
           , fco_arg = downgradeRole Representational Nominal arg
           , fco_res = downgradeRole Representational Nominal res }
    mkSubCo Coercion
    co = Bool -> SDoc -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> SDoc -> a -> a
    assertPpr (Coercion -> Role
    coercionRole Coercion
    co Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role
    Nominal) (Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    co SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Role -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (Coercion -> Role
    coercionRole Coercion
    co)) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                 Coercion -> Coercion
    SubCo Coercion
    co

    -- | Changes a role, but only a downgrade. See Note [Role twiddling functions]
    downgradeRole_maybe :: Role   -- ^ desired role
                        -> Role   -- ^ current role
                        -> Coercion -> Maybe Coercion
    -- In (downgradeRole_maybe dr cr co) it's a precondition that
    --                                   cr = coercionRole co

    downgradeRole_maybe :: Role -> Role -> Coercion -> Maybe Coercion
    downgradeRole_maybe Role
    Nominal          Role
    Nominal          Coercion
    co = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    co
    downgradeRole_maybe Role
    Nominal          Role
    _                Coercion
    _  = Maybe Coercion
    forall a. Maybe a
    Nothing

    downgradeRole_maybe Role
    Representational Role
    Nominal          Coercion
    co = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just ((() :: Constraint) => Coercion -> Coercion
    Coercion -> Coercion
    mkSubCo Coercion
    co)
    downgradeRole_maybe Role
    Representational Role
    Representational Coercion
    co = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    co
    downgradeRole_maybe Role
    Representational Role
    Phantom          Coercion
    _  = Maybe Coercion
    forall a. Maybe a
    Nothing

    downgradeRole_maybe Role
    Phantom          Role
    Phantom          Coercion
    co = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    co
    downgradeRole_maybe Role
    Phantom          Role
    _                Coercion
    co = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Coercion -> Coercion
    toPhantomCo Coercion
    co)

    -- | Like 'downgradeRole_maybe', but panics if the change isn't a downgrade.
    -- See Note [Role twiddling functions]
    downgradeRole :: Role  -- desired role
                  -> Role  -- current role
                  -> Coercion -> Coercion
    downgradeRole :: Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    r1 Role
    r2 Coercion
    co
      = case Role -> Role -> Coercion -> Maybe Coercion
    downgradeRole_maybe Role
    r1 Role
    r2 Coercion
    co of
          Just Coercion
    co' -> Coercion
    co'
          Maybe Coercion
    Nothing  -> String -> SDoc -> Coercion
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "downgradeRole" (Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    co)

    mkAxiomRuleCo :: CoAxiomRule -> [Coercion] -> Coercion
    mkAxiomRuleCo :: CoAxiomRule -> [Coercion] -> Coercion
    mkAxiomRuleCo = CoAxiomRule -> [Coercion] -> Coercion
    AxiomRuleCo

    -- | Make a "coercion between coercions".
    mkProofIrrelCo :: Role       -- ^ role of the created coercion, "r"
                   -> CoercionN  -- ^ :: phi1 ~N phi2
                   -> Coercion   -- ^ g1 :: phi1
                   -> Coercion   -- ^ g2 :: phi2
                   -> Coercion   -- ^ :: g1 ~r g2

    -- if the two coercion prove the same fact, I just don't care what
    -- the individual coercions are.
    mkProofIrrelCo :: Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkProofIrrelCo Role
    r Coercion
    co Coercion
    g  Coercion
    _ | Coercion -> Bool
    isGReflCo Coercion
    co  = Role -> Type -> Coercion
    mkReflCo Role
    r (Coercion -> Type
    mkCoercionTy Coercion
    g)
      -- kco is a kind coercion, thus @isGReflCo@ rather than @isReflCo@
    mkProofIrrelCo Role
    r Coercion
    kco        Coercion
    g1 Coercion
    g2 = UnivCoProvenance -> Role -> Type -> Type -> Coercion
    mkUnivCo (Coercion -> UnivCoProvenance
    ProofIrrelProv Coercion
    kco) Role
    r
                                                 (Coercion -> Type
    mkCoercionTy Coercion
    g1) (Coercion -> Type
    mkCoercionTy Coercion
    g2)

    {-
    %************************************************************************
    %*                                                                      *
       Roles
    %*                                                                      *
    %************************************************************************
    -}

    -- | Converts a coercion to be nominal, if possible.
    -- See Note [Role twiddling functions]
    setNominalRole_maybe :: Role -- of input coercion
                         -> Coercion -> Maybe CoercionN
    setNominalRole_maybe :: Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe Role
    r Coercion
    co
      | Role
    r Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role
    Nominal = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    co
      | Bool
    otherwise = Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co
      where
        setNominalRole_maybe_helper :: Coercion -> Maybe Coercion
    setNominalRole_maybe_helper (SubCo Coercion
    co)  = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    co
        setNominalRole_maybe_helper co :: Coercion
    co@(Refl Type
    _) = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just Coercion
    co
        setNominalRole_maybe_helper (GRefl Role
    _ Type
    ty MCoercion
    co) = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ Role -> Type -> MCoercion -> Coercion
    GRefl Role
    Nominal Type
    ty MCoercion
    co
        setNominalRole_maybe_helper (TyConAppCo Role
    Representational TyCon
    tc [Coercion]
    cos)
          = do { [Coercion]
    cos' <- (Role -> Coercion -> Maybe Coercion)
    -> [Role] -> [Coercion] -> Maybe [Coercion]
    forall (m :: * -> *) a b c.
    Applicative m =>
    (a -> b -> m c) -> [a] -> [b] -> m [c]
    zipWithM Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe (Role -> TyCon -> [Role]
    tyConRoleListX Role
    Representational TyCon
    tc) [Coercion]
    cos
               ; Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ Role -> TyCon -> [Coercion] -> Coercion
    TyConAppCo Role
    Nominal TyCon
    tc [Coercion]
    cos' }
        setNominalRole_maybe_helper co :: Coercion
    co@(FunCo { fco_role :: Coercion -> Role
    fco_role = Role
    Representational
                                              , fco_arg :: Coercion -> Coercion
    fco_arg = Coercion
    co1, fco_res :: Coercion -> Coercion
    fco_res = Coercion
    co2 })
          = do { Coercion
    co1' <- Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe Role
    Representational Coercion
    co1
               ; Coercion
    co2' <- Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe Role
    Representational Coercion
    co2
               ; Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ Coercion
    co { fco_role = Nominal, fco_arg = co1', fco_res = co2' }
               }
        setNominalRole_maybe_helper (SymCo Coercion
    co)
          = Coercion -> Coercion
    SymCo (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co
        setNominalRole_maybe_helper (TransCo Coercion
    co1 Coercion
    co2)
          = Coercion -> Coercion -> Coercion
    TransCo (Coercion -> Coercion -> Coercion)
    -> Maybe Coercion -> Maybe (Coercion -> Coercion)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co1 Maybe (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co2
        setNominalRole_maybe_helper (AppCo Coercion
    co1 Coercion
    co2)
          = Coercion -> Coercion -> Coercion
    AppCo (Coercion -> Coercion -> Coercion)
    -> Maybe Coercion -> Maybe (Coercion -> Coercion)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co1 Maybe (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Coercion
    co2
        setNominalRole_maybe_helper (ForAllCo CoVar
    tv Coercion
    kind_co Coercion
    co)
          = CoVar -> Coercion -> Coercion -> Coercion
    ForAllCo CoVar
    tv Coercion
    kind_co (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co
        setNominalRole_maybe_helper (SelCo CoSel
    cs Coercion
    co) =
          -- NB, this case recurses via setNominalRole_maybe, not
          -- setNominalRole_maybe_helper!
          case CoSel
    cs of
            SelTyCon Arity
    n Role
    _r ->
              -- Remember to update the role in SelTyCon to nominal;
              -- not doing this caused #23362.
              -- See the typing rule in Note [SelCo] in GHC.Core.TyCo.Rep.
              CoSel -> Coercion -> Coercion
    SelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    n Role
    Nominal) (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe (Coercion -> Role
    coercionRole Coercion
    co) Coercion
    co
            SelFun FunSel
    fs ->
              CoSel -> Coercion -> Coercion
    SelCo (FunSel -> CoSel
    SelFun FunSel
    fs) (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe (Coercion -> Role
    coercionRole Coercion
    co) Coercion
    co
            CoSel
    SelForAll ->
              String -> SDoc -> Maybe Coercion
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "setNominalRole_maybe: the coercion should already be nominal" (Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    co)
        setNominalRole_maybe_helper (InstCo Coercion
    co Coercion
    arg)
          = Coercion -> Coercion -> Coercion
    InstCo (Coercion -> Coercion -> Coercion)
    -> Maybe Coercion -> Maybe (Coercion -> Coercion)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Coercion -> Maybe Coercion
    setNominalRole_maybe_helper Coercion
    co Maybe (Coercion -> Coercion) -> Maybe Coercion -> Maybe Coercion
    forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Coercion
    arg
        setNominalRole_maybe_helper (UnivCo UnivCoProvenance
    prov Role
    _ Type
    co1 Type
    co2)
          | case UnivCoProvenance
    prov of PhantomProv Coercion
    _    -> Bool
    False  -- should always be phantom
                         ProofIrrelProv Coercion
    _ -> Bool
    True   -- it's always safe
                         PluginProv String
    _     -> Bool
    False  -- who knows? This choice is conservative.
                         CorePrepProv Bool
    _   -> Bool
    True
          = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ UnivCoProvenance -> Role -> Type -> Type -> Coercion
    UnivCo UnivCoProvenance
    prov Role
    Nominal Type
    co1 Type
    co2
        setNominalRole_maybe_helper Coercion
    _ = Maybe Coercion
    forall a. Maybe a
    Nothing

    -- | Make a phantom coercion between two types. The coercion passed
    -- in must be a nominal coercion between the kinds of the
    -- types.
    mkPhantomCo :: Coercion -> Type -> Type -> Coercion
    mkPhantomCo :: Coercion -> Type -> Type -> Coercion
    mkPhantomCo Coercion
    h Type
    t1 Type
    t2
      = UnivCoProvenance -> Role -> Type -> Type -> Coercion
    mkUnivCo (Coercion -> UnivCoProvenance
    PhantomProv Coercion
    h) Role
    Phantom Type
    t1 Type
    t2

    -- takes any coercion and turns it into a Phantom coercion
    toPhantomCo :: Coercion -> Coercion
    toPhantomCo :: Coercion -> Coercion
    toPhantomCo Coercion
    co
      = Coercion -> Type -> Type -> Coercion
    mkPhantomCo (Coercion -> Coercion
    mkKindCo Coercion
    co) Type
    ty1 Type
    ty2
      where Pair Type
    ty1 Type
    ty2 = Coercion -> Pair Type
    coercionKind Coercion
    co

    -- Convert args to a TyConAppCo Nominal to the same TyConAppCo Representational
    applyRoles :: TyCon -> [Coercion] -> [Coercion]
    applyRoles :: TyCon -> [Coercion] -> [Coercion]
    applyRoles = (Role -> Coercion -> Coercion)
    -> [Role] -> [Coercion] -> [Coercion]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith (Role -> Role -> Coercion -> Coercion
    `downgradeRole` Role
    Nominal) ([Role] -> [Coercion] -> [Coercion])
    -> (TyCon -> [Role]) -> TyCon -> [Coercion] -> [Coercion]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TyCon -> [Role]
    tyConRoleListRepresentational

    -- The Role parameter is the Role of the TyConAppCo
    -- defined here because this is intimately concerned with the implementation
    -- of TyConAppCo
    -- Always returns an infinite list (with a infinite tail of Nominal)
    tyConRolesX :: Role -> TyCon -> Infinite Role
    tyConRolesX :: Role -> TyCon -> Infinite Role
    tyConRolesX Role
    Representational TyCon
    tc = TyCon -> Infinite Role
    tyConRolesRepresentational TyCon
    tc
    tyConRolesX Role
    role             TyCon
    _  = Role -> Infinite Role
    forall a. a -> Infinite a
    Inf.repeat Role
    role

    tyConRoleListX :: Role -> TyCon -> [Role]
    tyConRoleListX :: Role -> TyCon -> [Role]
    tyConRoleListX Role
    role = Infinite Role -> [Role]
    forall a. Infinite a -> [a]
    Inf.toList (Infinite Role -> [Role])
    -> (TyCon -> Infinite Role) -> TyCon -> [Role]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Role -> TyCon -> Infinite Role
    tyConRolesX Role
    role

    -- Returns the roles of the parameters of a tycon, with an infinite tail
    -- of Nominal
    tyConRolesRepresentational :: TyCon -> Infinite Role
    tyConRolesRepresentational :: TyCon -> Infinite Role
    tyConRolesRepresentational TyCon
    tc = TyCon -> [Role]
    tyConRoles TyCon
    tc [Role] -> Infinite Role -> Infinite Role
    forall (f :: * -> *) a.
    Foldable f =>
    f a -> Infinite a -> Infinite a
    Inf.++ Role -> Infinite Role
    forall a. a -> Infinite a
    Inf.repeat Role
    Nominal

    -- Returns the roles of the parameters of a tycon, with an infinite tail
    -- of Nominal
    tyConRoleListRepresentational :: TyCon -> [Role]
    tyConRoleListRepresentational :: TyCon -> [Role]
    tyConRoleListRepresentational = Infinite Role -> [Role]
    forall a. Infinite a -> [a]
    Inf.toList (Infinite Role -> [Role])
    -> (TyCon -> Infinite Role) -> TyCon -> [Role]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TyCon -> Infinite Role
    tyConRolesRepresentational

    tyConRole :: Role -> TyCon -> Int -> Role
    tyConRole :: Role -> TyCon -> Arity -> Role
    tyConRole Role
    Nominal          TyCon
    _  Arity
    _ = Role
    Nominal
    tyConRole Role
    Phantom          TyCon
    _  Arity
    _ = Role
    Phantom
    tyConRole Role
    Representational TyCon
    tc Arity
    n = TyCon -> Infinite Role
    tyConRolesRepresentational TyCon
    tc Infinite Role -> Arity -> Role
    forall a. Infinite a -> Arity -> a
    Inf.!! Arity
    n

    funRole :: Role -> FunSel -> Role
    funRole :: Role -> FunSel -> Role
    funRole Role
    Nominal          FunSel
    _  = Role
    Nominal
    funRole Role
    Phantom          FunSel
    _  = Role
    Phantom
    funRole Role
    Representational FunSel
    fs = FunSel -> Role
    funRoleRepresentational FunSel
    fs

    funRoleRepresentational :: FunSel -> Role
    funRoleRepresentational :: FunSel -> Role
    funRoleRepresentational FunSel
    SelMult = Role
    Nominal
    funRoleRepresentational FunSel
    SelArg  = Role
    Representational
    funRoleRepresentational FunSel
    SelRes  = Role
    Representational

    ltRole :: Role -> Role -> Bool
    -- Is one role "less" than another?
    --     Nominal < Representational < Phantom
    ltRole :: Role -> Role -> Bool
    ltRole Role
    Phantom          Role
    _       = Bool
    False
    ltRole Role
    Representational Role
    Phantom = Bool
    True
    ltRole Role
    Representational Role
    _       = Bool
    False
    ltRole Role
    Nominal          Role
    Nominal = Bool
    False
    ltRole Role
    Nominal          Role
    _       = Bool
    True

    -------------------------------

    -- | like mkKindCo, but aggressively & recursively optimizes to avoid using
    -- a KindCo constructor. The output role is nominal.
    promoteCoercion :: Coercion -> CoercionN

    -- First cases handles anything that should yield refl.
    promoteCoercion :: Coercion -> Coercion
    promoteCoercion Coercion
    co = case Coercion
    co of

        Refl Type
    _ -> Type -> Coercion
    mkNomReflCo Type
    ki1

        GRefl Role
    _ Type
    _ MCoercion
    MRefl -> Type -> Coercion
    mkNomReflCo Type
    ki1

        GRefl Role
    _ Type
    _ (MCo Coercion
    co) -> Coercion
    co

        Coercion
    _ | Type
    ki1 Type -> Type -> Bool
    `eqType` Type
    ki2
          -> Type -> Coercion
    mkNomReflCo ((() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty1)
         -- No later branch should return refl
         -- The assert (False )s throughout
         -- are these cases explicitly, but they should never fire.

        TyConAppCo Role
    _ TyCon
    tc [Coercion]
    args
          | Just Coercion
    co' <- Coercion -> [Coercion] -> Maybe Coercion
    instCoercions (Type -> Coercion
    mkNomReflCo (TyCon -> Type
    tyConKind TyCon
    tc)) [Coercion]
    args
          -> Coercion
    co'
          | Bool
    otherwise
          -> Coercion -> Coercion
    mkKindCo Coercion
    co

        AppCo Coercion
    co1 Coercion
    arg
          | Just Coercion
    co' <- Pair Type -> Coercion -> Coercion -> Maybe Coercion
    instCoercion (Coercion -> Pair Type
    coercionKind (Coercion -> Coercion
    mkKindCo Coercion
    co1))
                                     (Coercion -> Coercion
    promoteCoercion Coercion
    co1) Coercion
    arg
          -> Coercion
    co'
          | Bool
    otherwise
          -> Coercion -> Coercion
    mkKindCo Coercion
    co

        ForAllCo CoVar
    tv Coercion
    _ Coercion
    g
          | CoVar -> Bool
    isTyVar CoVar
    tv
          -> Coercion -> Coercion
    promoteCoercion Coercion
    g

        ForAllCo {}
          -> Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert Bool
    False (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                -- (ForAllCo {} :: (forall cv.t1) ~ (forall cv.t2)
                -- The tyvar case is handled above, so the bound var is a
                -- a coercion variable. So both sides have kind Type
                -- (Note [Weird typing rule for ForAllTy] in GHC.Core.TyCo.Rep).
                -- So the result is Refl, and that should have been caught by
                -- the first equation above
             Type -> Coercion
    mkNomReflCo Type
    liftedTypeKind

        FunCo {} -> Coercion -> Coercion
    mkKindCo Coercion
    co
           -- We can get Type~Constraint or Constraint~Type
           -- from FunCo {} :: (a -> (b::Type)) ~ (a -=> (b'::Constraint))

        CoVarCo {}     -> Coercion -> Coercion
    mkKindCo Coercion
    co
        HoleCo {}      -> Coercion -> Coercion
    mkKindCo Coercion
    co
        AxiomInstCo {} -> Coercion -> Coercion
    mkKindCo Coercion
    co
        AxiomRuleCo {} -> Coercion -> Coercion
    mkKindCo Coercion
    co

        UnivCo (PhantomProv Coercion
    kco)    Role
    _ Type
    _ Type
    _ -> Coercion
    kco
        UnivCo (ProofIrrelProv Coercion
    kco) Role
    _ Type
    _ Type
    _ -> Coercion
    kco
        UnivCo (PluginProv String
    _)       Role
    _ Type
    _ Type
    _ -> Coercion -> Coercion
    mkKindCo Coercion
    co
        UnivCo (CorePrepProv Bool
    _)     Role
    _ Type
    _ Type
    _ -> Coercion -> Coercion
    mkKindCo Coercion
    co

        SymCo Coercion
    g
          -> Coercion -> Coercion
    mkSymCo (Coercion -> Coercion
    promoteCoercion Coercion
    g)

        TransCo Coercion
    co1 Coercion
    co2
          -> Coercion -> Coercion -> Coercion
    mkTransCo (Coercion -> Coercion
    promoteCoercion Coercion
    co1) (Coercion -> Coercion
    promoteCoercion Coercion
    co2)

        SelCo CoSel
    n Coercion
    co1
          | Just Coercion
    co' <- (() :: Constraint) => CoSel -> Coercion -> Maybe Coercion
    CoSel -> Coercion -> Maybe Coercion
    mkSelCo_maybe CoSel
    n Coercion
    co1
          -> Coercion -> Coercion
    promoteCoercion Coercion
    co'

          | Bool
    otherwise
          -> Coercion -> Coercion
    mkKindCo Coercion
    co

        LRCo LeftOrRight
    lr Coercion
    co1
          | Just (Coercion
    lco, Coercion
    rco) <- Coercion -> Maybe (Coercion, Coercion)
    splitAppCo_maybe Coercion
    co1
          -> case LeftOrRight
    lr of
               LeftOrRight
    CLeft  -> Coercion -> Coercion
    promoteCoercion Coercion
    lco
               LeftOrRight
    CRight -> Coercion -> Coercion
    promoteCoercion Coercion
    rco

          | Bool
    otherwise
          -> Coercion -> Coercion
    mkKindCo Coercion
    co

        InstCo Coercion
    g Coercion
    _
          | Type -> Bool
    isForAllTy_ty Type
    ty1
          -> Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Type -> Bool
    isForAllTy_ty Type
    ty2) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
             Coercion -> Coercion
    promoteCoercion Coercion
    g
          | Bool
    otherwise
          -> Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert Bool
    False (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
             Type -> Coercion
    mkNomReflCo Type
    liftedTypeKind
               -- See Note [Weird typing rule for ForAllTy] in GHC.Core.TyCo.Rep

        KindCo Coercion
    _
          -> Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert Bool
    False (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $ -- See the first equation above
             Type -> Coercion
    mkNomReflCo Type
    liftedTypeKind

        SubCo Coercion
    g
          -> Coercion -> Coercion
    promoteCoercion Coercion
    g

      where
        Pair Type
    ty1 Type
    ty2 = Coercion -> Pair Type
    coercionKind Coercion
    co
        ki1 :: Type
    ki1 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty1
        ki2 :: Type
    ki2 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty2

    -- | say @g = promoteCoercion h@. Then, @instCoercion g w@ yields @Just g'@,
    -- where @g' = promoteCoercion (h w)@.
    -- fails if this is not possible, if @g@ coerces between a forall and an ->
    -- or if second parameter has a representational role and can't be used
    -- with an InstCo.
    instCoercion :: Pair Type -- g :: lty ~ rty
                 -> CoercionN  -- ^  must be nominal
                 -> Coercion
                 -> Maybe CoercionN
    instCoercion :: Pair Type -> Coercion -> Coercion -> Maybe Coercion
    instCoercion (Pair Type
    lty Type
    rty) Coercion
    g Coercion
    w
      | (Type -> Bool
    isForAllTy_ty Type
    lty Bool -> Bool -> Bool
    && Type -> Bool
    isForAllTy_ty Type
    rty)
      Bool -> Bool -> Bool
    || (Type -> Bool
    isForAllTy_co Type
    lty Bool -> Bool -> Bool
    && Type -> Bool
    isForAllTy_co Type
    rty)
      , Just Coercion
    w' <- Role -> Coercion -> Maybe Coercion
    setNominalRole_maybe (Coercion -> Role
    coercionRole Coercion
    w) Coercion
    w
        -- g :: (forall t1. t2) ~ (forall t1. t3)
        -- w :: s1 ~ s2
        -- returns mkInstCo g w' :: t2 [t1 |-> s1 ] ~ t3 [t1 |-> s2]
      = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ Coercion -> Coercion -> Coercion
    mkInstCo Coercion
    g Coercion
    w'

      | Type -> Bool
    isFunTy Type
    lty Bool -> Bool -> Bool
    && Type -> Bool
    isFunTy Type
    rty
        -- g :: (t1 -> t2) ~ (t3 -> t4)
        -- returns t2 ~ t4
      = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (FunSel -> CoSel
    SelFun FunSel
    SelRes) Coercion
    g -- extract result type

      | Bool
    otherwise -- one forall, one funty...
      = Maybe Coercion
    forall a. Maybe a
    Nothing

    -- | Repeated use of 'instCoercion'
    instCoercions :: CoercionN -> [Coercion] -> Maybe CoercionN
    instCoercions :: Coercion -> [Coercion] -> Maybe Coercion
    instCoercions Coercion
    g [Coercion]
    ws
      = let arg_ty_pairs :: [Pair Type]
    arg_ty_pairs = (Coercion -> Pair Type) -> [Coercion] -> [Pair Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Pair Type
    coercionKind [Coercion]
    ws in
        (Pair Type, Coercion) -> Coercion
    forall a b. (a, b) -> b
    snd ((Pair Type, Coercion) -> Coercion)
    -> Maybe (Pair Type, Coercion) -> Maybe Coercion
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ((Pair Type, Coercion)
     -> (Pair Type, Coercion) -> Maybe (Pair Type, Coercion))
    -> (Pair Type, Coercion)
    -> [(Pair Type, Coercion)]
    -> Maybe (Pair Type, Coercion)
    forall (t :: * -> *) (m :: * -> *) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m b
    foldM (Pair Type, Coercion)
    -> (Pair Type, Coercion) -> Maybe (Pair Type, Coercion)
    go (Coercion -> Pair Type
    coercionKind Coercion
    g, Coercion
    g) ([Pair Type] -> [Coercion] -> [(Pair Type, Coercion)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Pair Type]
    arg_ty_pairs [Coercion]
    ws)
      where
        go :: (Pair Type, Coercion) -> (Pair Type, Coercion)
           -> Maybe (Pair Type, Coercion)
        go :: (Pair Type, Coercion)
    -> (Pair Type, Coercion) -> Maybe (Pair Type, Coercion)
    go (Pair Type
    g_tys, Coercion
    g) (Pair Type
    w_tys, Coercion
    w)
          = do { Coercion
    g' <- Pair Type -> Coercion -> Coercion -> Maybe Coercion
    instCoercion Pair Type
    g_tys Coercion
    g Coercion
    w
               ; (Pair Type, Coercion) -> Maybe (Pair Type, Coercion)
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ((() :: Constraint) => Type -> Type -> Type
    Type -> Type -> Type
    piResultTy (Type -> Type -> Type) -> Pair Type -> Pair (Type -> Type)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Pair Type
    g_tys Pair (Type -> Type) -> Pair Type -> Pair Type
    forall a b. Pair (a -> b) -> Pair a -> Pair b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Pair Type
    w_tys, Coercion
    g') }

    -- | 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 :: Coercion
    -> Role -> Type -> Type -> Coercion -> Coercion -> Coercion
    castCoercionKind2 Coercion
    g Role
    r Type
    t1 Type
    t2 Coercion
    h1 Coercion
    h2
      = Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceRightCo Role
    r Type
    t2 Coercion
    h2 (Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceLeftCo Role
    r Type
    t1 Coercion
    h1 Coercion
    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 :: Coercion -> Role -> Type -> Type -> Coercion -> Coercion
    castCoercionKind1 Coercion
    g Role
    r Type
    t1 Type
    t2 Coercion
    h
      = case Coercion
    g of
          Refl {} -> Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Role
    r Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role
    Nominal) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $ -- Refl is always Nominal
                     Type -> Coercion
    mkNomReflCo (Type -> Coercion -> Type
    mkCastTy Type
    t2 Coercion
    h)
          GRefl Role
    _ Type
    _ MCoercion
    mco -> case MCoercion
    mco of
               MCoercion
    MRefl       -> Role -> Type -> Coercion
    mkReflCo Role
    r (Type -> Coercion -> Type
    mkCastTy Type
    t2 Coercion
    h)
               MCo Coercion
    kind_co -> Role -> Type -> MCoercion -> Coercion
    GRefl Role
    r (Type -> Coercion -> Type
    mkCastTy Type
    t1 Coercion
    h) (MCoercion -> Coercion) -> MCoercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                              Coercion -> MCoercion
    MCo (Coercion -> Coercion
    mkSymCo Coercion
    h Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    kind_co Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    h)
          Coercion
    _ -> Coercion
    -> Role -> Type -> Type -> Coercion -> Coercion -> Coercion
    castCoercionKind2 Coercion
    g Role
    r Type
    t1 Type
    t2 Coercion
    h Coercion
    h

    -- | Creates a new coercion with both of its types casted by different casts
    -- @castCoercionKind g h1 h2@, where @g :: t1 ~r t2@,
    -- has type @(t1 |> h1) ~r (t2 |> h2)@.
    -- @h1@ and @h2@ must be nominal.
    -- It calls @coercionKindRole@, so it's quite inefficient (which 'I' stands for)
    -- Use @castCoercionKind2@ instead if @t1@, @t2@, and @r@ are known beforehand.
    castCoercionKind :: Coercion -> CoercionN -> CoercionN -> Coercion
    castCoercionKind :: Coercion -> Coercion -> Coercion -> Coercion
    castCoercionKind Coercion
    g Coercion
    h1 Coercion
    h2
      = Coercion
    -> Role -> Type -> Type -> Coercion -> Coercion -> Coercion
    castCoercionKind2 Coercion
    g Role
    r Type
    t1 Type
    t2 Coercion
    h1 Coercion
    h2
      where
        (Pair Type
    t1 Type
    t2, Role
    r) = Coercion -> (Pair Type, Role)
    coercionKindRole Coercion
    g

    mkPiCos :: Role -> [Var] -> Coercion -> Coercion
    mkPiCos :: Role -> [CoVar] -> Coercion -> Coercion
    mkPiCos Role
    r [CoVar]
    vs Coercion
    co = (CoVar -> Coercion -> Coercion) -> Coercion -> [CoVar] -> Coercion
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr (Role -> CoVar -> Coercion -> Coercion
    mkPiCo Role
    r) Coercion
    co [CoVar]
    vs

    -- | Make a forall 'Coercion', where both types related by the coercion
    -- are quantified over the same variable.
    mkPiCo  :: Role -> Var -> Coercion -> Coercion
    mkPiCo :: Role -> CoVar -> Coercion -> Coercion
    mkPiCo Role
    r CoVar
    v Coercion
    co | CoVar -> Bool
    isTyVar CoVar
    v = [CoVar] -> Coercion -> Coercion
    mkHomoForAllCos [CoVar
    v] Coercion
    co
                  | CoVar -> Bool
    isCoVar CoVar
    v = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Bool -> Bool
    not (CoVar
    v CoVar -> VarSet -> Bool
    `elemVarSet` Coercion -> VarSet
    tyCoVarsOfCo Coercion
    co)) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                      -- We didn't call mkForAllCo here because if v does not appear
                      -- in co, the argument coercion will be nominal. But here we
                      -- want it to be r. It is only called in 'mkPiCos', which is
                      -- only used in GHC.Core.Opt.Simplify.Utils, where we are sure for
                      -- now (Aug 2018) v won't occur in co.
                                Role -> CoVar -> Coercion -> Coercion
    mkFunResCo Role
    r CoVar
    v Coercion
    co
                  | Bool
    otherwise = Role -> CoVar -> Coercion -> Coercion
    mkFunResCo Role
    r CoVar
    v Coercion
    co

    mkFunResCo :: Role -> Id -> Coercion -> Coercion
    -- Given res_co :: res1 ~ res2,
    --   mkFunResCo r m arg res_co :: (arg -> res1) ~r (arg -> res2)
    -- Reflexive in the multiplicity argument
    mkFunResCo :: Role -> CoVar -> Coercion -> Coercion
    mkFunResCo Role
    role CoVar
    id Coercion
    res_co
      = (() :: Constraint) =>
    Role -> Coercion -> Coercion -> Coercion -> Coercion
    Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkFunCoNoFTF Role
    role Coercion
    mult Coercion
    arg_co Coercion
    res_co
      where
        arg_co :: Coercion
    arg_co = Role -> Type -> Coercion
    mkReflCo Role
    role (CoVar -> Type
    varType CoVar
    id)
        mult :: Coercion
    mult   = Type -> Coercion
    multToCo (CoVar -> Type
    varMult CoVar
    id)

    -- mkCoCast (c :: s1 ~?r t1) (g :: (s1 ~?r t1) ~#R (s2 ~?r t2)) :: s2 ~?r t2
    -- The first coercion might be lifted or unlifted; thus the ~? above
    -- Lifted and unlifted equalities take different numbers of arguments,
    -- so we have to make sure to supply the right parameter to decomposeCo.
    -- Also, note that the role of the first coercion is the same as the role of
    -- the equalities related by the second coercion. The second coercion is
    -- itself always representational.
    mkCoCast :: Coercion -> CoercionR -> Coercion
    mkCoCast :: Coercion -> Coercion -> Coercion
    mkCoCast Coercion
    c Coercion
    g
      | (Coercion
    g2:Coercion
    g1:[Coercion]
    _) <- [Coercion] -> [Coercion]
    forall a. [a] -> [a]
    reverse [Coercion]
    co_list
      = Coercion -> Coercion
    mkSymCo Coercion
    g1 Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    c Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    g2

      | Bool
    otherwise
      = String -> SDoc -> Coercion
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "mkCoCast" (Coercion -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Coercion
    g SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ Pair Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (Coercion -> Pair Type
    coercionKind Coercion
    g))
      where
        -- g  :: (s1 ~# t1) ~# (s2 ~# t2)
        -- g1 :: s1 ~# s2
        -- g2 :: t1 ~# t2
        (TyCon
    tc, [Type]
    _) = Type -> (TyCon, [Type])
    splitTyConApp (Coercion -> Type
    coercionLKind Coercion
    g)
        co_list :: [Coercion]
    co_list = Arity -> Coercion -> Infinite Role -> [Coercion]
    decomposeCo (TyCon -> Arity
    tyConArity TyCon
    tc) Coercion
    g (TyCon -> Infinite Role
    tyConRolesRepresentational TyCon
    tc)

    {- Note [castCoercionKind1]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    castCoercionKind1 deals with the very important special case of castCoercionKind2
    where the two kind coercions are identical.  In that case we can exploit the
    situation where the main coercion is reflexive, via the special cases for Refl
    and GRefl.

    This is important when rewriting  (ty |> co). We rewrite ty, yielding
       fco :: ty ~ ty'
    and now we want a coercion xco between
       xco :: (ty |> co) ~ (ty' |> co)
    That's exactly what castCoercionKind1 does.  And it's very very common for
    fco to be Refl.  In that case we do NOT want to get some terrible composition
    of mkLeftCoherenceCo and mkRightCoherenceCo, which is what castCoercionKind2
    has to do in its full generality.  See #18413.
    -}

    {-
    %************************************************************************
    %*                                                                      *
                Newtypes
    %*                                                                      *
    %************************************************************************
    -}

    -- | If `instNewTyCon_maybe T ts = Just (rep_ty, co)`
    --   then `co :: T ts ~R# rep_ty`
    --
    -- Checks for a newtype, and for being saturated
    instNewTyCon_maybe :: TyCon -> [Type] -> Maybe (Type, Coercion)
    instNewTyCon_maybe :: TyCon -> [Type] -> Maybe (Type, Coercion)
    instNewTyCon_maybe TyCon
    tc [Type]
    tys
      | Just ([CoVar]
    tvs, Type
    ty, CoAxiom Unbranched
    co_tc) <- TyCon -> Maybe ([CoVar], Type, CoAxiom Unbranched)
    unwrapNewTyConEtad_maybe TyCon
    tc  -- Check for newtype
      , [CoVar]
    tvs [CoVar] -> [Type] -> Bool
    forall a b. [a] -> [b] -> Bool
    `leLength` [Type]
    tys                                    -- Check saturated enough
      = (Type, Coercion) -> Maybe (Type, Coercion)
    forall a. a -> Maybe a
    Just ([CoVar] -> Type -> [Type] -> Type
    (() :: Constraint) => [CoVar] -> Type -> [Type] -> Type
    applyTysX [CoVar]
    tvs Type
    ty [Type]
    tys, Role -> CoAxiom Unbranched -> [Type] -> [Coercion] -> Coercion
    mkUnbranchedAxInstCo Role
    Representational CoAxiom Unbranched
    co_tc [Type]
    tys [])
      | Bool
    otherwise
      = Maybe (Type, Coercion)
    forall a. Maybe a
    Nothing

    {-
    ************************************************************************
    *                                                                      *
             Type normalisation
    *                                                                      *
    ************************************************************************
    -}

    -- | A function to check if we can reduce a type by one step. Used
    -- with 'topNormaliseTypeX'.
    type NormaliseStepper ev = RecTcChecker
                             -> TyCon     -- tc
                             -> [Type]    -- tys
                             -> NormaliseStepResult ev

    -- | The result of stepping in a normalisation function.
    -- See 'topNormaliseTypeX'.
    data NormaliseStepResult ev
      = NS_Done   -- ^ Nothing more to do
      | NS_Abort  -- ^ Utter failure. The outer function should fail too.
      | NS_Step RecTcChecker Type ev    -- ^ We stepped, yielding new bits;
                                        -- ^ ev is evidence;
                                        -- Usually a co :: old type ~ new type
      deriving ((forall a b.
     (a -> b) -> NormaliseStepResult a -> NormaliseStepResult b)
    -> (forall a b.
        a -> NormaliseStepResult b -> NormaliseStepResult a)
    -> Functor NormaliseStepResult
    forall a b. a -> NormaliseStepResult b -> NormaliseStepResult a
    forall a b.
    (a -> b) -> NormaliseStepResult a -> NormaliseStepResult b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    $cfmap :: forall a b.
    (a -> b) -> NormaliseStepResult a -> NormaliseStepResult b
    fmap :: forall a b.
    (a -> b) -> NormaliseStepResult a -> NormaliseStepResult b
    $c<$ :: forall a b. a -> NormaliseStepResult b -> NormaliseStepResult a
    <$ :: forall a b. a -> NormaliseStepResult b -> NormaliseStepResult a
    Functor)

    instance Outputable ev => Outputable (NormaliseStepResult ev) where
      ppr :: NormaliseStepResult ev -> SDoc
    ppr NormaliseStepResult ev
    NS_Done           = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "NS_Done"
      ppr NormaliseStepResult ev
    NS_Abort          = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "NS_Abort"
      ppr (NS_Step RecTcChecker
    _ Type
    ty ev
    ev) = [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep [String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "NS_Step", Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty, ev -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr ev
    ev]

    -- | Try one stepper and then try the next, if the first doesn't make
    -- progress.
    -- So if it returns NS_Done, it means that both steppers are satisfied
    composeSteppers :: NormaliseStepper ev -> NormaliseStepper ev
                    -> NormaliseStepper ev
    composeSteppers :: forall ev.
    NormaliseStepper ev -> NormaliseStepper ev -> NormaliseStepper ev
    composeSteppers NormaliseStepper ev
    step1 NormaliseStepper ev
    step2 RecTcChecker
    rec_nts TyCon
    tc [Type]
    tys
      = case NormaliseStepper ev
    step1 RecTcChecker
    rec_nts TyCon
    tc [Type]
    tys of
          success :: NormaliseStepResult ev
    success@(NS_Step {}) -> NormaliseStepResult ev
    success
          NormaliseStepResult ev
    NS_Done              -> NormaliseStepper ev
    step2 RecTcChecker
    rec_nts TyCon
    tc [Type]
    tys
          NormaliseStepResult ev
    NS_Abort             -> NormaliseStepResult ev
    forall ev. NormaliseStepResult ev
    NS_Abort

    -- | A 'NormaliseStepper' that unwraps newtypes, careful not to fall into
    -- a loop. If it would fall into a loop, it produces 'NS_Abort'.
    unwrapNewTypeStepper :: NormaliseStepper Coercion
    unwrapNewTypeStepper :: NormaliseStepper Coercion
    unwrapNewTypeStepper RecTcChecker
    rec_nts TyCon
    tc [Type]
    tys
      | Just (Type
    ty', Coercion
    co) <- TyCon -> [Type] -> Maybe (Type, Coercion)
    instNewTyCon_maybe TyCon
    tc [Type]
    tys
      = -- pprTrace "unNS" (ppr tc <+> ppr (getUnique tc) <+> ppr tys $$ ppr ty' $$ ppr rec_nts) $
        case RecTcChecker -> TyCon -> Maybe RecTcChecker
    checkRecTc RecTcChecker
    rec_nts TyCon
    tc of
          Just RecTcChecker
    rec_nts' -> RecTcChecker -> Type -> Coercion -> NormaliseStepResult Coercion
    forall ev. RecTcChecker -> Type -> ev -> NormaliseStepResult ev
    NS_Step RecTcChecker
    rec_nts' Type
    ty' Coercion
    co
          Maybe RecTcChecker
    Nothing       -> NormaliseStepResult Coercion
    forall ev. NormaliseStepResult ev
    NS_Abort

      | Bool
    otherwise
      = NormaliseStepResult Coercion
    forall ev. NormaliseStepResult ev
    NS_Done

    -- | A general function for normalising the top-level of a type. It continues
    -- to use the provided 'NormaliseStepper' until that function fails, and then
    -- this function returns. The roles of the coercions produced by the
    -- 'NormaliseStepper' must all be the same, which is the role returned from
    -- the call to 'topNormaliseTypeX'.
    --
    -- Typically ev is Coercion.
    --
    -- If topNormaliseTypeX step plus ty = Just (ev, ty')
    -- then ty ~ev1~ t1 ~ev2~ t2 ... ~evn~ ty'
    -- and ev = ev1 `plus` ev2 `plus` ... `plus` evn
    -- If it returns Nothing then no newtype unwrapping could happen
    topNormaliseTypeX :: NormaliseStepper ev
                      -> (ev -> ev -> ev)
                      -> Type -> Maybe (ev, Type)
    topNormaliseTypeX :: forall ev.
    NormaliseStepper ev -> (ev -> ev -> ev) -> Type -> Maybe (ev, Type)
    topNormaliseTypeX NormaliseStepper ev
    stepper ev -> ev -> ev
    plus Type
    ty
     | Just (TyCon
    tc, [Type]
    tys) <- (() :: Constraint) => Type -> Maybe (TyCon, [Type])
    Type -> Maybe (TyCon, [Type])
    splitTyConApp_maybe Type
    ty
     -- SPJ: The default threshold for initRecTc is 100 which is extremely dangerous
     --      for certain type synonyms, we should think about reducing it (see #20990)
     , NS_Step RecTcChecker
    rec_nts Type
    ty' ev
    ev <- NormaliseStepper ev
    stepper RecTcChecker
    initRecTc TyCon
    tc [Type]
    tys
     = RecTcChecker -> ev -> Type -> Maybe (ev, Type)
    go RecTcChecker
    rec_nts ev
    ev Type
    ty'
     | Bool
    otherwise
     = Maybe (ev, Type)
    forall a. Maybe a
    Nothing
     where
        go :: RecTcChecker -> ev -> Type -> Maybe (ev, Type)
    go RecTcChecker
    rec_nts ev
    ev Type
    ty
          | Just (TyCon
    tc, [Type]
    tys) <- (() :: Constraint) => Type -> Maybe (TyCon, [Type])
    Type -> Maybe (TyCon, [Type])
    splitTyConApp_maybe Type
    ty
          = case NormaliseStepper ev
    stepper RecTcChecker
    rec_nts TyCon
    tc [Type]
    tys of
              NS_Step RecTcChecker
    rec_nts' Type
    ty' ev
    ev' -> RecTcChecker -> ev -> Type -> Maybe (ev, Type)
    go RecTcChecker
    rec_nts' (ev
    ev ev -> ev -> ev
    `plus` ev
    ev') Type
    ty'
              NormaliseStepResult ev
    NS_Done  -> (ev, Type) -> Maybe (ev, Type)
    forall a. a -> Maybe a
    Just (ev
    ev, Type
    ty)
              NormaliseStepResult ev
    NS_Abort -> Maybe (ev, Type)
    forall a. Maybe a
    Nothing

          | Bool
    otherwise
          = (ev, Type) -> Maybe (ev, Type)
    forall a. a -> Maybe a
    Just (ev
    ev, Type
    ty)

    topNormaliseNewType_maybe :: Type -> Maybe (Coercion, Type)
    -- ^ Sometimes we want to look through a @newtype@ and get its associated coercion.
    -- This function strips off @newtype@ layers enough to reveal something that isn't
    -- a @newtype@.  Specifically, here's the invariant:
    --
    -- > topNormaliseNewType_maybe rec_nts ty = Just (co, ty')
    --
    -- then (a)  @co : ty ~R ty'@.
    --      (b)  ty' is not a newtype.
    --
    -- The function returns @Nothing@ for non-@newtypes@,
    -- or unsaturated applications
    --
    -- This function does *not* look through type families, because it has no access to
    -- the type family environment. If you do have that at hand, consider to use
    -- topNormaliseType_maybe, which should be a drop-in replacement for
    -- topNormaliseNewType_maybe
    -- If topNormliseNewType_maybe ty = Just (co, ty'), then co : ty ~R ty'
    topNormaliseNewType_maybe :: Type -> Maybe (Coercion, Type)
    topNormaliseNewType_maybe Type
    ty
      = NormaliseStepper Coercion
    -> (Coercion -> Coercion -> Coercion)
    -> Type
    -> Maybe (Coercion, Type)
    forall ev.
    NormaliseStepper ev -> (ev -> ev -> ev) -> Type -> Maybe (ev, Type)
    topNormaliseTypeX NormaliseStepper Coercion
    unwrapNewTypeStepper Coercion -> Coercion -> Coercion
    mkTransCo Type
    ty

    {-
    %************************************************************************
    %*                                                                      *
                       Comparison of coercions
    %*                                                                      *
    %************************************************************************
    -}

    -- | Syntactic equality of coercions
    eqCoercion :: Coercion -> Coercion -> Bool
    eqCoercion :: Coercion -> Coercion -> Bool
    eqCoercion = Type -> Type -> Bool
    eqType (Type -> Type -> Bool)
    -> (Coercion -> Type) -> Coercion -> Coercion -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` Coercion -> Type
    coercionType

    -- | Compare two 'Coercion's, with respect to an RnEnv2
    eqCoercionX :: RnEnv2 -> Coercion -> Coercion -> Bool
    eqCoercionX :: RnEnv2 -> Coercion -> Coercion -> Bool
    eqCoercionX RnEnv2
    env = RnEnv2 -> Type -> Type -> Bool
    eqTypeX RnEnv2
    env (Type -> Type -> Bool)
    -> (Coercion -> Type) -> Coercion -> Coercion -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` Coercion -> Type
    coercionType

    {-
    %************************************************************************
    %*                                                                      *
                       "Lifting" substitution
               [(TyCoVar,Coercion)] -> Type -> Coercion
    %*                                                                      *
    %************************************************************************

    Note [Lifting coercions over types: liftCoSubst]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The KPUSH rule deals with this situation
       data T a = K (a -> Maybe a)
       g :: T t1 ~ T t2
       x :: t1 -> Maybe t1

       case (K @t1 x) |> g of
         K (y:t2 -> Maybe t2) -> rhs

    We want to push the coercion inside the constructor application.
    So we do this

       g' :: t1~t2  =  SelCo (SelTyCon 0) g

       case K @t2 (x |> g' -> Maybe g') of
         K (y:t2 -> Maybe t2) -> rhs

    The crucial operation is that we
      * take the type of K's argument: a -> Maybe a
      * and substitute g' for a
    thus giving *coercion*.  This is what liftCoSubst does.

    In the presence of kind coercions, this is a bit
    of a hairy operation. So, we refer you to the paper introducing kind coercions,
    available at www.cis.upenn.edu/~sweirich/papers/fckinds-extended.pdf

    Note [extendLiftingContextEx]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Consider we have datatype
      K :: /\k. /\a::k. P -> T k  -- P be some type
      g :: T k1 ~ T k2

      case (K @k1 @t1 x) |> g of
        K y -> rhs

    We want to push the coercion inside the constructor application.
    We first get the coercion mapped by the universal type variable k:
       lc = k |-> SelCo (SelTyCon 0) g :: k1~k2

    Here, the important point is that the kind of a is coerced, and P might be
    dependent on the existential type variable a.
    Thus we first get the coercion of a's kind
       g2 = liftCoSubst lc k :: k1 ~ k2

    Then we store a new mapping into the lifting context
       lc2 = a |-> (t1 ~ t1 |> g2), lc

    So later when we can correctly deal with the argument type P
       liftCoSubst lc2 P :: P [k|->k1][a|->t1] ~ P[k|->k2][a |-> (t1|>g2)]

    This is exactly what extendLiftingContextEx does.
    * For each (tyvar:k, ty) pair, we product the mapping
        tyvar |-> (ty ~ ty |> (liftCoSubst lc k))
    * For each (covar:s1~s2, ty) pair, we produce the mapping
        covar |-> (co ~ co')
        co' = Sym (liftCoSubst lc s1) ;; covar ;; liftCoSubst lc s2 :: s1'~s2'

    This follows the lifting context extension definition in the
    "FC with Explicit Kind Equality" paper.
    -}

    -- ----------------------------------------------------
    -- See Note [Lifting coercions over types: liftCoSubst]
    -- ----------------------------------------------------

    data LiftingContext = LC Subst LiftCoEnv
      -- in optCoercion, we need to lift when optimizing InstCo.
      -- See Note [Optimising InstCo] in GHC.Core.Coercion.Opt
      -- We thus propagate the substitution from GHC.Core.Coercion.Opt here.

    instance Outputable LiftingContext where
      ppr :: LiftingContext -> SDoc
    ppr (LC Subst
    _ LiftCoEnv
    env) = SDoc -> Arity -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "LiftingContext:") Arity
    2 (LiftCoEnv -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr LiftCoEnv
    env)

    type LiftCoEnv = VarEnv Coercion
         -- Maps *type variables* to *coercions*.
         -- That's the whole point of this function!
         -- Also maps coercion variables to ProofIrrelCos.

    -- like liftCoSubstWith, but allows for existentially-bound types as well
    liftCoSubstWithEx :: Role          -- desired role for output coercion
                      -> [TyVar]       -- universally quantified tyvars
                      -> [Coercion]    -- coercions to substitute for those
                      -> [TyCoVar]     -- existentially quantified tycovars
                      -> [Type]        -- types and coercions to be bound to ex vars
                      -> (Type -> Coercion, [Type]) -- (lifting function, converted ex args)
    liftCoSubstWithEx :: Role
    -> [CoVar]
    -> [Coercion]
    -> [CoVar]
    -> [Type]
    -> (Type -> Coercion, [Type])
    liftCoSubstWithEx Role
    role [CoVar]
    univs [Coercion]
    omegas [CoVar]
    exs [Type]
    rhos
      = let theta :: LiftingContext
    theta = [(CoVar, Coercion)] -> LiftingContext
    mkLiftingContext (String -> [CoVar] -> [Coercion] -> [(CoVar, Coercion)]
    forall a b. (() :: Constraint) => String -> [a] -> [b] -> [(a, b)]
    zipEqual String
    "liftCoSubstWithExU" [CoVar]
    univs [Coercion]
    omegas)
            psi :: LiftingContext
    psi   = LiftingContext -> [(CoVar, Type)] -> LiftingContext
    extendLiftingContextEx LiftingContext
    theta (String -> [CoVar] -> [Type] -> [(CoVar, Type)]
    forall a b. (() :: Constraint) => String -> [a] -> [b] -> [(a, b)]
    zipEqual String
    "liftCoSubstWithExX" [CoVar]
    exs [Type]
    rhos)
        in (LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    psi Role
    role, (() :: Constraint) => Subst -> [Type] -> [Type]
    Subst -> [Type] -> [Type]
    substTys (LiftingContext -> Subst
    lcSubstRight LiftingContext
    psi) ([CoVar] -> [Type]
    mkTyCoVarTys [CoVar]
    exs))

    liftCoSubstWith :: Role -> [TyCoVar] -> [Coercion] -> Type -> Coercion
    liftCoSubstWith :: Role -> [CoVar] -> [Coercion] -> Type -> Coercion
    liftCoSubstWith Role
    r [CoVar]
    tvs [Coercion]
    cos Type
    ty
      = (() :: Constraint) => Role -> LiftingContext -> Type -> Coercion
    Role -> LiftingContext -> Type -> Coercion
    liftCoSubst Role
    r ([(CoVar, Coercion)] -> LiftingContext
    mkLiftingContext ([(CoVar, Coercion)] -> LiftingContext)
    -> [(CoVar, Coercion)] -> LiftingContext
    forall a b. (a -> b) -> a -> b
    $ String -> [CoVar] -> [Coercion] -> [(CoVar, Coercion)]
    forall a b. (() :: Constraint) => String -> [a] -> [b] -> [(a, b)]
    zipEqual String
    "liftCoSubstWith" [CoVar]
    tvs [Coercion]
    cos) Type
    ty

    -- | @liftCoSubst role lc ty@ produces a coercion (at role @role@)
    -- that coerces between @lc_left(ty)@ and @lc_right(ty)@, where
    -- @lc_left@ is a substitution mapping type variables to the left-hand
    -- types of the mapped coercions in @lc@, and similar for @lc_right@.
    liftCoSubst :: HasDebugCallStack => Role -> LiftingContext -> Type -> Coercion
    {-# INLINE liftCoSubst #-}
    -- Inlining this function is worth 2% of allocation in T9872d,
    liftCoSubst :: (() :: Constraint) => Role -> LiftingContext -> Type -> Coercion
    liftCoSubst Role
    r lc :: LiftingContext
    lc@(LC Subst
    subst LiftCoEnv
    env) Type
    ty
      | LiftCoEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv LiftCoEnv
    env = Role -> Type -> Coercion
    mkReflCo Role
    r ((() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy Subst
    subst Type
    ty)
      | Bool
    otherwise         = LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    lc Role
    r Type
    ty

    emptyLiftingContext :: InScopeSet -> LiftingContext
    emptyLiftingContext :: InScopeSet -> LiftingContext
    emptyLiftingContext InScopeSet
    in_scope = Subst -> LiftCoEnv -> LiftingContext
    LC (InScopeSet -> Subst
    mkEmptySubst InScopeSet
    in_scope) LiftCoEnv
    forall a. VarEnv a
    emptyVarEnv

    mkLiftingContext :: [(TyCoVar,Coercion)] -> LiftingContext
    mkLiftingContext :: [(CoVar, Coercion)] -> LiftingContext
    mkLiftingContext [(CoVar, Coercion)]
    pairs
      = Subst -> LiftCoEnv -> LiftingContext
    LC (InScopeSet -> Subst
    mkEmptySubst (InScopeSet -> Subst) -> InScopeSet -> Subst
    forall a b. (a -> b) -> a -> b
    $ VarSet -> InScopeSet
    mkInScopeSet (VarSet -> InScopeSet) -> VarSet -> InScopeSet
    forall a b. (a -> b) -> a -> b
    $ [Coercion] -> VarSet
    tyCoVarsOfCos (((CoVar, Coercion) -> Coercion)
    -> [(CoVar, Coercion)] -> [Coercion]
    forall a b. (a -> b) -> [a] -> [b]
    map (CoVar, Coercion) -> Coercion
    forall a b. (a, b) -> b
    snd [(CoVar, Coercion)]
    pairs))
           ([(CoVar, Coercion)] -> LiftCoEnv
    forall a. [(CoVar, a)] -> VarEnv a
    mkVarEnv [(CoVar, Coercion)]
    pairs)

    mkSubstLiftingContext :: Subst -> LiftingContext
    mkSubstLiftingContext :: Subst -> LiftingContext
    mkSubstLiftingContext Subst
    subst = Subst -> LiftCoEnv -> LiftingContext
    LC Subst
    subst LiftCoEnv
    forall a. VarEnv a
    emptyVarEnv

    -- | Extend a lifting context with a new mapping.
    extendLiftingContext :: LiftingContext  -- ^ original LC
                         -> TyCoVar         -- ^ new variable to map...
                         -> Coercion        -- ^ ...to this lifted version
                         -> LiftingContext
        -- mappings to reflexive coercions are just substitutions
    extendLiftingContext :: LiftingContext -> CoVar -> Coercion -> LiftingContext
    extendLiftingContext (LC Subst
    subst LiftCoEnv
    env) CoVar
    tv Coercion
    arg
      | Just (Type
    ty, Role
    _) <- Coercion -> Maybe (Type, Role)
    isReflCo_maybe Coercion
    arg
      = Subst -> LiftCoEnv -> LiftingContext
    LC (Subst -> CoVar -> Type -> Subst
    extendTCvSubst Subst
    subst CoVar
    tv Type
    ty) LiftCoEnv
    env
      | Bool
    otherwise
      = Subst -> LiftCoEnv -> LiftingContext
    LC Subst
    subst (LiftCoEnv -> CoVar -> Coercion -> LiftCoEnv
    forall a. VarEnv a -> CoVar -> a -> VarEnv a
    extendVarEnv LiftCoEnv
    env CoVar
    tv Coercion
    arg)

    -- | Extend a lifting context with a new mapping, and extend the in-scope set
    extendLiftingContextAndInScope :: LiftingContext  -- ^ Original LC
                                   -> TyCoVar         -- ^ new variable to map...
                                   -> Coercion        -- ^ to this coercion
                                   -> LiftingContext
    extendLiftingContextAndInScope :: LiftingContext -> CoVar -> Coercion -> LiftingContext
    extendLiftingContextAndInScope (LC Subst
    subst LiftCoEnv
    env) CoVar
    tv Coercion
    co
      = LiftingContext -> CoVar -> Coercion -> LiftingContext
    extendLiftingContext (Subst -> LiftCoEnv -> LiftingContext
    LC (Subst -> VarSet -> Subst
    extendSubstInScopeSet Subst
    subst (Coercion -> VarSet
    tyCoVarsOfCo Coercion
    co)) LiftCoEnv
    env) CoVar
    tv Coercion
    co

    -- | Extend a lifting context with existential-variable bindings.
    -- See Note [extendLiftingContextEx]
    extendLiftingContextEx :: LiftingContext    -- ^ original lifting context
                           -> [(TyCoVar,Type)]  -- ^ ex. var / value pairs
                           -> LiftingContext
    -- Note that this is more involved than extendLiftingContext. That function
    -- takes a coercion to extend with, so it's assumed that the caller has taken
    -- into account any of the kind-changing stuff worried about here.
    extendLiftingContextEx :: LiftingContext -> [(CoVar, Type)] -> LiftingContext
    extendLiftingContextEx LiftingContext
    lc [] = LiftingContext
    lc
    extendLiftingContextEx lc :: LiftingContext
    lc@(LC Subst
    subst LiftCoEnv
    env) ((CoVar
    v,Type
    ty):[(CoVar, Type)]
    rest)
    -- This function adds bindings for *Nominal* coercions. Why? Because it
    -- works with existentially bound variables, which are considered to have
    -- nominal roles.
      | CoVar -> Bool
    isTyVar CoVar
    v
      = let lc' :: LiftingContext
    lc' = Subst -> LiftCoEnv -> LiftingContext
    LC (Subst
    subst Subst -> VarSet -> Subst
    `extendSubstInScopeSet` Type -> VarSet
    tyCoVarsOfType Type
    ty)
                     (LiftCoEnv -> CoVar -> Coercion -> LiftCoEnv
    forall a. VarEnv a -> CoVar -> a -> VarEnv a
    extendVarEnv LiftCoEnv
    env CoVar
    v (Coercion -> LiftCoEnv) -> Coercion -> LiftCoEnv
    forall a b. (a -> b) -> a -> b
    $
                      Role -> Type -> Coercion -> Coercion
    mkGReflRightCo Role
    Nominal
                                     Type
    ty
                                     (LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    lc Role
    Nominal (CoVar -> Type
    tyVarKind CoVar
    v)))
        in LiftingContext -> [(CoVar, Type)] -> LiftingContext
    extendLiftingContextEx LiftingContext
    lc' [(CoVar, Type)]
    rest
      | CoercionTy Coercion
    co <- Type
    ty
      = -- co      :: s1 ~r s2
        -- lift_s1 :: s1 ~r s1'
        -- lift_s2 :: s2 ~r s2'
        -- kco     :: (s1 ~r s2) ~N (s1' ~r s2')
        Bool -> LiftingContext -> LiftingContext
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isCoVar CoVar
    v) (LiftingContext -> LiftingContext)
    -> LiftingContext -> LiftingContext
    forall a b. (a -> b) -> a -> b
    $
        let (Type
    _, Type
    _, Type
    s1, Type
    s2, Role
    r) = (() :: Constraint) => CoVar -> (Type, Type, Type, Type, Role)
    CoVar -> (Type, Type, Type, Type, Role)
    coVarKindsTypesRole CoVar
    v
            lift_s1 :: Coercion
    lift_s1 = LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    lc Role
    r Type
    s1
            lift_s2 :: Coercion
    lift_s2 = LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    lc Role
    r Type
    s2
            kco :: Coercion
    kco     = (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    Nominal (Role -> TyCon
    equalityTyCon Role
    r)
                                   [ Coercion -> Coercion
    mkKindCo Coercion
    lift_s1, Coercion -> Coercion
    mkKindCo Coercion
    lift_s2
                                   , Coercion
    lift_s1         , Coercion
    lift_s2          ]
            lc' :: LiftingContext
    lc'     = Subst -> LiftCoEnv -> LiftingContext
    LC (Subst
    subst Subst -> VarSet -> Subst
    `extendSubstInScopeSet` Coercion -> VarSet
    tyCoVarsOfCo Coercion
    co)
                         (LiftCoEnv -> CoVar -> Coercion -> LiftCoEnv
    forall a. VarEnv a -> CoVar -> a -> VarEnv a
    extendVarEnv LiftCoEnv
    env CoVar
    v
                            (Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkProofIrrelCo Role
    Nominal Coercion
    kco Coercion
    co (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                              (Coercion -> Coercion
    mkSymCo Coercion
    lift_s1) Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    co Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    lift_s2))
        in LiftingContext -> [(CoVar, Type)] -> LiftingContext
    extendLiftingContextEx LiftingContext
    lc' [(CoVar, Type)]
    rest
      | Bool
    otherwise
      = String -> SDoc -> LiftingContext
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "extendLiftingContextEx" (CoVar -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoVar
    v SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "|->" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty)

    -- | Erase the environments in a lifting context
    zapLiftingContext :: LiftingContext -> LiftingContext
    zapLiftingContext :: LiftingContext -> LiftingContext
    zapLiftingContext (LC Subst
    subst LiftCoEnv
    _) = Subst -> LiftCoEnv -> LiftingContext
    LC (Subst -> Subst
    zapSubst Subst
    subst) LiftCoEnv
    forall a. VarEnv a
    emptyVarEnv

    -- | Like 'substForAllCoBndr', but works on a lifting context
    substForAllCoBndrUsingLC :: Bool
                                -> (Coercion -> Coercion)
                                -> LiftingContext -> TyCoVar -> Coercion
                                -> (LiftingContext, TyCoVar, Coercion)
    substForAllCoBndrUsingLC :: Bool
    -> (Coercion -> Coercion)
    -> LiftingContext
    -> CoVar
    -> Coercion
    -> (LiftingContext, CoVar, Coercion)
    substForAllCoBndrUsingLC Bool
    sym Coercion -> Coercion
    sco (LC Subst
    subst LiftCoEnv
    lc_env) CoVar
    tv Coercion
    co
      = (Subst -> LiftCoEnv -> LiftingContext
    LC Subst
    subst' LiftCoEnv
    lc_env, CoVar
    tv', Coercion
    co')
      where
        (Subst
    subst', CoVar
    tv', Coercion
    co') = Bool
    -> (Coercion -> Coercion)
    -> Subst
    -> CoVar
    -> Coercion
    -> (Subst, CoVar, Coercion)
    substForAllCoBndrUsing Bool
    sym Coercion -> Coercion
    sco Subst
    subst CoVar
    tv Coercion
    co

    -- | The \"lifting\" operation which substitutes coercions for type
    --   variables in a type to produce a coercion.
    --
    --   For the inverse operation, see 'liftCoMatch'
    ty_co_subst :: LiftingContext -> Role -> Type -> Coercion
    ty_co_subst :: LiftingContext -> Role -> Type -> Coercion
    ty_co_subst !LiftingContext
    lc Role
    role Type
    ty
        -- !lc: making this function strict in lc allows callers to
        -- pass its two components separately, rather than boxing them.
        -- Unfortunately, Boxity Analysis concludes that we need lc boxed
        -- because it's used that way in liftCoSubstTyVarBndrUsing.
      = Role -> Type -> Coercion
    go Role
    role Type
    ty
      where
        go :: Role -> Type -> Coercion
        go :: Role -> Type -> Coercion
    go Role
    r Type
    ty                 | Just Type
    ty' <- Type -> Maybe Type
    coreView Type
    ty
                                = Role -> Type -> Coercion
    go Role
    r Type
    ty'
        go Role
    Phantom Type
    ty           = Type -> Coercion
    lift_phantom Type
    ty
        go Role
    r (TyVarTy CoVar
    tv)       = String -> Maybe Coercion -> Coercion
    forall a. HasCallStack => String -> Maybe a -> a
    expectJust String
    "ty_co_subst bad roles" (Maybe Coercion -> Coercion) -> Maybe Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                                  LiftingContext -> Role -> CoVar -> Maybe Coercion
    liftCoSubstTyVar LiftingContext
    lc Role
    r CoVar
    tv
        go Role
    r (AppTy Type
    ty1 Type
    ty2)    = Coercion -> Coercion -> Coercion
    mkAppCo (Role -> Type -> Coercion
    go Role
    r Type
    ty1) (Role -> Type -> Coercion
    go Role
    Nominal Type
    ty2)
        go Role
    r (TyConApp TyCon
    tc [Type]
    tys)  = (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    r TyCon
    tc ((Role -> Type -> Coercion) -> [Role] -> [Type] -> [Coercion]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Role -> Type -> Coercion
    go (Role -> TyCon -> [Role]
    tyConRoleListX Role
    r TyCon
    tc) [Type]
    tys)
        go Role
    r (FunTy FunTyFlag
    af Type
    w Type
    t1 Type
    t2) = (() :: Constraint) =>
    Role -> FunTyFlag -> Coercion -> Coercion -> Coercion -> Coercion
    Role -> FunTyFlag -> Coercion -> Coercion -> Coercion -> Coercion
    mkFunCo1 Role
    r FunTyFlag
    af (Role -> Type -> Coercion
    go Role
    Nominal Type
    w) (Role -> Type -> Coercion
    go Role
    r Type
    t1) (Role -> Type -> Coercion
    go Role
    r Type
    t2)
        go Role
    r t :: Type
    t@(ForAllTy (Bndr CoVar
    v ForAllTyFlag
    _) Type
    ty)
           = let (LiftingContext
    lc', CoVar
    v', Coercion
    h) = LiftingContext -> CoVar -> (LiftingContext, CoVar, Coercion)
    liftCoSubstVarBndr LiftingContext
    lc CoVar
    v
                 body_co :: Coercion
    body_co = LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    lc' Role
    r Type
    ty in
             if CoVar -> Bool
    isTyVar CoVar
    v' Bool -> Bool -> Bool
    || CoVar -> Coercion -> Bool
    almostDevoidCoVarOfCo CoVar
    v' Coercion
    body_co
               -- Lifting a ForAllTy over a coercion variable could fail as ForAllCo
               -- imposes an extra restriction on where a covar can appear. See last
               -- wrinkle in Note [Unused coercion variable in ForAllCo].
               -- We specifically check for this and panic because we know that
               -- there's a hole in the type system here, and we'd rather panic than
               -- fall into it.
             then CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo CoVar
    v' Coercion
    h Coercion
    body_co
             else String -> SDoc -> Coercion
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "ty_co_subst: covar is not almost devoid" (Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    t)
        go Role
    r ty :: Type
    ty@(LitTy {})     = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (Role
    r Role -> Role -> Bool
    forall a. Eq a => a -> a -> Bool
    == Role
    Nominal) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
                                 Type -> Coercion
    mkNomReflCo Type
    ty
        go Role
    r (CastTy Type
    ty Coercion
    co)    = Coercion -> Coercion -> Coercion -> Coercion
    castCoercionKind (Role -> Type -> Coercion
    go Role
    r Type
    ty) (LiftingContext -> Coercion -> Coercion
    substLeftCo LiftingContext
    lc Coercion
    co)
                                                            (LiftingContext -> Coercion -> Coercion
    substRightCo LiftingContext
    lc Coercion
    co)
        go Role
    r (CoercionTy Coercion
    co)   = Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkProofIrrelCo Role
    r Coercion
    kco (LiftingContext -> Coercion -> Coercion
    substLeftCo LiftingContext
    lc Coercion
    co)
                                                      (LiftingContext -> Coercion -> Coercion
    substRightCo LiftingContext
    lc Coercion
    co)
          where kco :: Coercion
    kco = Role -> Type -> Coercion
    go Role
    Nominal (Coercion -> Type
    coercionType Coercion
    co)

        lift_phantom :: Type -> Coercion
    lift_phantom Type
    ty = Coercion -> Type -> Type -> Coercion
    mkPhantomCo (Role -> Type -> Coercion
    go Role
    Nominal ((() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty))
                                      ((() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy (LiftingContext -> Subst
    lcSubstLeft  LiftingContext
    lc) Type
    ty)
                                      ((() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy (LiftingContext -> Subst
    lcSubstRight LiftingContext
    lc) Type
    ty)

    {-
    Note [liftCoSubstTyVar]
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    This function can fail if a coercion in the environment is of too low a role.

    liftCoSubstTyVar is called from two places: in liftCoSubst (naturally), and
    also in matchAxiom in GHC.Core.Coercion.Opt. From liftCoSubst, the so-called lifting
    lemma guarantees that the roles work out. If we fail in this
    case, we really should panic -- something is deeply wrong. But, in matchAxiom,
    failing is fine. matchAxiom is trying to find a set of coercions
    that match, but it may fail, and this is healthy behavior.
    -}

    -- See Note [liftCoSubstTyVar]
    liftCoSubstTyVar :: LiftingContext -> Role -> TyVar -> Maybe Coercion
    liftCoSubstTyVar :: LiftingContext -> Role -> CoVar -> Maybe Coercion
    liftCoSubstTyVar (LC Subst
    subst LiftCoEnv
    env) Role
    r CoVar
    v
      | Just Coercion
    co_arg <- LiftCoEnv -> CoVar -> Maybe Coercion
    forall a. VarEnv a -> CoVar -> Maybe a
    lookupVarEnv LiftCoEnv
    env CoVar
    v
      = Role -> Role -> Coercion -> Maybe Coercion
    downgradeRole_maybe Role
    r (Coercion -> Role
    coercionRole Coercion
    co_arg) Coercion
    co_arg

      | Bool
    otherwise
      = Coercion -> Maybe Coercion
    forall a. a -> Maybe a
    Just (Coercion -> Maybe Coercion) -> Coercion -> Maybe Coercion
    forall a b. (a -> b) -> a -> b
    $ Role -> Type -> Coercion
    mkReflCo Role
    r (Subst -> CoVar -> Type
    substTyVar Subst
    subst CoVar
    v)

    {- Note [liftCoSubstVarBndr]
       ~~~~~~~~~~~~~~~~~~~~~~~~~
    callback:
      'liftCoSubstVarBndrUsing' needs to be general enough to work in two
      situations:

        - in this module, which manipulates 'Coercion's, and
        - in GHC.Core.FamInstEnv, where we work with 'Reduction's, which contain
          a coercion as well as a type.

      To achieve this, we require that the return type of the 'callback' function
      contain a coercion within it. This is witnessed by the first argument
      to 'liftCoSubstVarBndrUsing': a getter, which allows us to retrieve
      the coercion inside the return type. Thus:

        - in this module, we simply pass 'id' as the getter,
        - in GHC.Core.FamInstEnv, we pass 'reductionCoercion' as the getter.

    liftCoSubstTyVarBndrUsing:
      Given
        forall tv:k. t
      We want to get
        forall (tv:k1) (kind_co :: k1 ~ k2) body_co

      We lift the kind k to get the kind_co
        kind_co = ty_co_subst k :: k1 ~ k2

      Now in the LiftingContext, we add the new mapping
        tv |-> (tv :: k1) ~ ((tv |> kind_co) :: k2)

    liftCoSubstCoVarBndrUsing:
      Given
        forall cv:(s1 ~ s2). t
      We want to get
        forall (cv:s1'~s2') (kind_co :: (s1'~s2') ~ (t1 ~ t2)) body_co

      We lift s1 and s2 respectively to get
        eta1 :: s1' ~ t1
        eta2 :: s2' ~ t2
      And
        kind_co = TyConAppCo Nominal (~#) eta1 eta2

      Now in the liftingContext, we add the new mapping
        cv |-> (cv :: s1' ~ s2') ~ ((sym eta1;cv;eta2) :: t1 ~ t2)
    -}

    -- See Note [liftCoSubstVarBndr]
    liftCoSubstVarBndr :: LiftingContext -> TyCoVar
                       -> (LiftingContext, TyCoVar, Coercion)
    liftCoSubstVarBndr :: LiftingContext -> CoVar -> (LiftingContext, CoVar, Coercion)
    liftCoSubstVarBndr LiftingContext
    lc CoVar
    tv
      = (Coercion -> Coercion)
    -> (LiftingContext -> Type -> Coercion)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, Coercion)
    forall r.
    (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    liftCoSubstVarBndrUsing Coercion -> Coercion
    forall a. a -> a
    id LiftingContext -> Type -> Coercion
    callback LiftingContext
    lc CoVar
    tv
      where
        callback :: LiftingContext -> Type -> Coercion
    callback LiftingContext
    lc' Type
    ty' = LiftingContext -> Role -> Type -> Coercion
    ty_co_subst LiftingContext
    lc' Role
    Nominal Type
    ty'

    -- the callback must produce a nominal coercion
    liftCoSubstVarBndrUsing :: (r -> CoercionN)              -- ^ coercion getter
                            -> (LiftingContext -> Type -> r) -- ^ callback
                            -> LiftingContext -> TyCoVar
                            -> (LiftingContext, TyCoVar, r)
    liftCoSubstVarBndrUsing :: forall r.
    (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    liftCoSubstVarBndrUsing r -> Coercion
    view_co LiftingContext -> Type -> r
    fun LiftingContext
    lc CoVar
    old_var
      | CoVar -> Bool
    isTyVar CoVar
    old_var
      = (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    forall r.
    (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    liftCoSubstTyVarBndrUsing r -> Coercion
    view_co LiftingContext -> Type -> r
    fun LiftingContext
    lc CoVar
    old_var
      | Bool
    otherwise
      = (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    forall r.
    (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    liftCoSubstCoVarBndrUsing r -> Coercion
    view_co LiftingContext -> Type -> r
    fun LiftingContext
    lc CoVar
    old_var

    -- Works for tyvar binder
    liftCoSubstTyVarBndrUsing :: (r -> CoercionN)              -- ^ coercion getter
                              -> (LiftingContext -> Type -> r) -- ^ callback
                              -> LiftingContext -> TyVar
                              -> (LiftingContext, TyVar, r)
    liftCoSubstTyVarBndrUsing :: forall r.
    (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    liftCoSubstTyVarBndrUsing r -> Coercion
    view_co LiftingContext -> Type -> r
    fun lc :: LiftingContext
    lc@(LC Subst
    subst LiftCoEnv
    cenv) CoVar
    old_var
      = Bool -> (LiftingContext, CoVar, r) -> (LiftingContext, CoVar, r)
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isTyVar CoVar
    old_var) ((LiftingContext, CoVar, r) -> (LiftingContext, CoVar, r))
    -> (LiftingContext, CoVar, r) -> (LiftingContext, CoVar, r)
    forall a b. (a -> b) -> a -> b
    $
        ( Subst -> LiftCoEnv -> LiftingContext
    LC (Subst
    subst Subst -> CoVar -> Subst
    `extendSubstInScope` CoVar
    new_var) LiftCoEnv
    new_cenv
        , CoVar
    new_var, r
    stuff )
      where
        old_kind :: Type
    old_kind = CoVar -> Type
    tyVarKind CoVar
    old_var
        stuff :: r
    stuff    = LiftingContext -> Type -> r
    fun LiftingContext
    lc Type
    old_kind
        eta :: Coercion
    eta      = r -> Coercion
    view_co r
    stuff
        k1 :: Type
    k1       = Coercion -> Type
    coercionLKind Coercion
    eta
        new_var :: CoVar
    new_var  = InScopeSet -> CoVar -> CoVar
    uniqAway (Subst -> InScopeSet
    getSubstInScope Subst
    subst) (CoVar -> Type -> CoVar
    setVarType CoVar
    old_var Type
    k1)

        lifted :: Coercion
    lifted   = Role -> Type -> Coercion -> Coercion
    mkGReflRightCo Role
    Nominal (CoVar -> Type
    TyVarTy CoVar
    new_var) Coercion
    eta
                   -- :: new_var ~ new_var |> eta
        new_cenv :: LiftCoEnv
    new_cenv = LiftCoEnv -> CoVar -> Coercion -> LiftCoEnv
    forall a. VarEnv a -> CoVar -> a -> VarEnv a
    extendVarEnv LiftCoEnv
    cenv CoVar
    old_var Coercion
    lifted

    -- Works for covar binder
    liftCoSubstCoVarBndrUsing :: (r -> CoercionN)              -- ^ coercion getter
                              -> (LiftingContext -> Type -> r) -- ^ callback
                              -> LiftingContext -> CoVar
                              -> (LiftingContext, CoVar, r)
    liftCoSubstCoVarBndrUsing :: forall r.
    (r -> Coercion)
    -> (LiftingContext -> Type -> r)
    -> LiftingContext
    -> CoVar
    -> (LiftingContext, CoVar, r)
    liftCoSubstCoVarBndrUsing r -> Coercion
    view_co LiftingContext -> Type -> r
    fun lc :: LiftingContext
    lc@(LC Subst
    subst LiftCoEnv
    cenv) CoVar
    old_var
      = Bool -> (LiftingContext, CoVar, r) -> (LiftingContext, CoVar, r)
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isCoVar CoVar
    old_var) ((LiftingContext, CoVar, r) -> (LiftingContext, CoVar, r))
    -> (LiftingContext, CoVar, r) -> (LiftingContext, CoVar, r)
    forall a b. (a -> b) -> a -> b
    $
        ( Subst -> LiftCoEnv -> LiftingContext
    LC (Subst
    subst Subst -> CoVar -> Subst
    `extendSubstInScope` CoVar
    new_var) LiftCoEnv
    new_cenv
        , CoVar
    new_var, r
    stuff )
      where
        old_kind :: Type
    old_kind = CoVar -> Type
    coVarKind CoVar
    old_var
        stuff :: r
    stuff    = LiftingContext -> Type -> r
    fun LiftingContext
    lc Type
    old_kind
        eta :: Coercion
    eta      = r -> Coercion
    view_co r
    stuff
        k1 :: Type
    k1       = Coercion -> Type
    coercionLKind Coercion
    eta
        new_var :: CoVar
    new_var  = InScopeSet -> CoVar -> CoVar
    uniqAway (Subst -> InScopeSet
    getSubstInScope Subst
    subst) (CoVar -> Type -> CoVar
    setVarType CoVar
    old_var Type
    k1)

        -- old_var :: s1  ~r s2
        -- eta     :: (s1' ~r s2') ~N (t1 ~r t2)
        -- eta1    :: s1' ~r t1
        -- eta2    :: s2' ~r t2
        -- co1     :: s1' ~r s2'
        -- co2     :: t1  ~r t2
        -- lifted  :: co1 ~N co2

        role :: Role
    role   = CoVar -> Role
    coVarRole CoVar
    old_var
        eta' :: Coercion
    eta'   = Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    role Role
    Nominal Coercion
    eta
        eta1 :: Coercion
    eta1   = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    2 Role
    role) Coercion
    eta'
        eta2 :: Coercion
    eta2   = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    3 Role
    role) Coercion
    eta'

        co1 :: Coercion
    co1     = CoVar -> Coercion
    mkCoVarCo CoVar
    new_var
        co2 :: Coercion
    co2     = Coercion -> Coercion
    mkSymCo Coercion
    eta1 Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    co1 Coercion -> Coercion -> Coercion
    `mkTransCo` Coercion
    eta2
        lifted :: Coercion
    lifted  = Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkProofIrrelCo Role
    Nominal Coercion
    eta Coercion
    co1 Coercion
    co2

        new_cenv :: LiftCoEnv
    new_cenv = LiftCoEnv -> CoVar -> Coercion -> LiftCoEnv
    forall a. VarEnv a -> CoVar -> a -> VarEnv a
    extendVarEnv LiftCoEnv
    cenv CoVar
    old_var Coercion
    lifted

    -- | Is a var in the domain of a lifting context?
    isMappedByLC :: TyCoVar -> LiftingContext -> Bool
    isMappedByLC :: CoVar -> LiftingContext -> Bool
    isMappedByLC CoVar
    tv (LC Subst
    _ LiftCoEnv
    env) = CoVar
    tv CoVar -> LiftCoEnv -> Bool
    forall a. CoVar -> VarEnv a -> Bool
    `elemVarEnv` LiftCoEnv
    env

    -- If [a |-> g] is in the substitution and g :: t1 ~ t2, substitute a for t1
    -- If [a |-> (g1, g2)] is in the substitution, substitute a for g1
    substLeftCo :: LiftingContext -> Coercion -> Coercion
    substLeftCo :: LiftingContext -> Coercion -> Coercion
    substLeftCo LiftingContext
    lc Coercion
    co
      = (() :: Constraint) => Subst -> Coercion -> Coercion
    Subst -> Coercion -> Coercion
    substCo (LiftingContext -> Subst
    lcSubstLeft LiftingContext
    lc) Coercion
    co

    -- Ditto, but for t2 and g2
    substRightCo :: LiftingContext -> Coercion -> Coercion
    substRightCo :: LiftingContext -> Coercion -> Coercion
    substRightCo LiftingContext
    lc Coercion
    co
      = (() :: Constraint) => Subst -> Coercion -> Coercion
    Subst -> Coercion -> Coercion
    substCo (LiftingContext -> Subst
    lcSubstRight LiftingContext
    lc) Coercion
    co

    -- | Apply "sym" to all coercions in a 'LiftCoEnv'
    swapLiftCoEnv :: LiftCoEnv -> LiftCoEnv
    swapLiftCoEnv :: LiftCoEnv -> LiftCoEnv
    swapLiftCoEnv = (Coercion -> Coercion) -> LiftCoEnv -> LiftCoEnv
    forall a b. (a -> b) -> VarEnv a -> VarEnv b
    mapVarEnv Coercion -> Coercion
    mkSymCo

    lcSubstLeft :: LiftingContext -> Subst
    lcSubstLeft :: LiftingContext -> Subst
    lcSubstLeft (LC Subst
    subst LiftCoEnv
    lc_env) = Subst -> LiftCoEnv -> Subst
    liftEnvSubstLeft Subst
    subst LiftCoEnv
    lc_env

    lcSubstRight :: LiftingContext -> Subst
    lcSubstRight :: LiftingContext -> Subst
    lcSubstRight (LC Subst
    subst LiftCoEnv
    lc_env) = Subst -> LiftCoEnv -> Subst
    liftEnvSubstRight Subst
    subst LiftCoEnv
    lc_env

    liftEnvSubstLeft :: Subst -> LiftCoEnv -> Subst
    liftEnvSubstLeft :: Subst -> LiftCoEnv -> Subst
    liftEnvSubstLeft = (forall a. Pair a -> a) -> Subst -> LiftCoEnv -> Subst
    liftEnvSubst Pair a -> a
    forall a. Pair a -> a
    pFst

    liftEnvSubstRight :: Subst -> LiftCoEnv -> Subst
    liftEnvSubstRight :: Subst -> LiftCoEnv -> Subst
    liftEnvSubstRight = (forall a. Pair a -> a) -> Subst -> LiftCoEnv -> Subst
    liftEnvSubst Pair a -> a
    forall a. Pair a -> a
    pSnd

    liftEnvSubst :: (forall a. Pair a -> a) -> Subst -> LiftCoEnv -> Subst
    liftEnvSubst :: (forall a. Pair a -> a) -> Subst -> LiftCoEnv -> Subst
    liftEnvSubst forall a. Pair a -> a
    selector Subst
    subst LiftCoEnv
    lc_env
      = Subst -> Subst -> Subst
    composeTCvSubst (InScopeSet -> IdSubstEnv -> TvSubstEnv -> LiftCoEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    emptyIdSubstEnv TvSubstEnv
    tenv LiftCoEnv
    cenv) Subst
    subst
      where
        pairs :: [(Unique, Coercion)]
    pairs            = LiftCoEnv -> [(Unique, Coercion)]
    forall key elt. UniqFM key elt -> [(Unique, elt)]
    nonDetUFMToList LiftCoEnv
    lc_env
                           -- It's OK to use nonDetUFMToList here because we
                           -- immediately forget the ordering by creating
                           -- a VarEnv
        ([(Unique, Type)]
    tpairs, [(Unique, Coercion)]
    cpairs) = ((Unique, Coercion) -> Either (Unique, Type) (Unique, Coercion))
    -> [(Unique, Coercion)] -> ([(Unique, Type)], [(Unique, Coercion)])
    forall a b c. (a -> Either b c) -> [a] -> ([b], [c])
    partitionWith (Unique, Coercion) -> Either (Unique, Type) (Unique, Coercion)
    ty_or_co [(Unique, Coercion)]
    pairs
        -- Make sure the in-scope set is wide enough to cover the range of the
        -- substitution (#22235).
        in_scope :: InScopeSet
    in_scope         = VarSet -> InScopeSet
    mkInScopeSet (VarSet -> InScopeSet) -> VarSet -> InScopeSet
    forall a b. (a -> b) -> a -> b
    $
                           [Type] -> VarSet
    tyCoVarsOfTypes (((Unique, Type) -> Type) -> [(Unique, Type)] -> [Type]
    forall a b. (a -> b) -> [a] -> [b]
    map (Unique, Type) -> Type
    forall a b. (a, b) -> b
    snd [(Unique, Type)]
    tpairs) VarSet -> VarSet -> VarSet
    `unionVarSet`
                           [Coercion] -> VarSet
    tyCoVarsOfCos (((Unique, Coercion) -> Coercion)
    -> [(Unique, Coercion)] -> [Coercion]
    forall a b. (a -> b) -> [a] -> [b]
    map (Unique, Coercion) -> Coercion
    forall a b. (a, b) -> b
    snd [(Unique, Coercion)]
    cpairs)
        tenv :: TvSubstEnv
    tenv             = [(Unique, Type)] -> TvSubstEnv
    forall a. [(Unique, a)] -> VarEnv a
    mkVarEnv_Directly [(Unique, Type)]
    tpairs
        cenv :: LiftCoEnv
    cenv             = [(Unique, Coercion)] -> LiftCoEnv
    forall a. [(Unique, a)] -> VarEnv a
    mkVarEnv_Directly [(Unique, Coercion)]
    cpairs

        ty_or_co :: (Unique, Coercion) -> Either (Unique, Type) (Unique, Coercion)
        ty_or_co :: (Unique, Coercion) -> Either (Unique, Type) (Unique, Coercion)
    ty_or_co (Unique
    u, Coercion
    co)
          | Just Coercion
    equality_co <- Type -> Maybe Coercion
    isCoercionTy_maybe Type
    equality_ty
          = (Unique, Coercion) -> Either (Unique, Type) (Unique, Coercion)
    forall a b. b -> Either a b
    Right (Unique
    u, Coercion
    equality_co)
          | Bool
    otherwise
          = (Unique, Type) -> Either (Unique, Type) (Unique, Coercion)
    forall a b. a -> Either a b
    Left (Unique
    u, Type
    equality_ty)
          where
            equality_ty :: Type
    equality_ty = Pair Type -> Type
    forall a. Pair a -> a
    selector (Coercion -> Pair Type
    coercionKind Coercion
    co)

    -- | Extract the underlying substitution from the LiftingContext
    lcSubst :: LiftingContext -> Subst
    lcSubst :: LiftingContext -> Subst
    lcSubst (LC Subst
    subst LiftCoEnv
    _) = Subst
    subst

    -- | Get the 'InScopeSet' from a 'LiftingContext'
    lcInScopeSet :: LiftingContext -> InScopeSet
    lcInScopeSet :: LiftingContext -> InScopeSet
    lcInScopeSet (LC Subst
    subst LiftCoEnv
    _) = Subst -> InScopeSet
    getSubstInScope Subst
    subst

    {-
    %************************************************************************
    %*                                                                      *
                Sequencing on coercions
    %*                                                                      *
    %************************************************************************
    -}

    seqMCo :: MCoercion -> ()
    seqMCo :: MCoercion -> ()
    seqMCo MCoercion
    MRefl    = ()
    seqMCo (MCo Coercion
    co) = Coercion -> ()
    seqCo Coercion
    co

    seqCo :: Coercion -> ()
    seqCo :: Coercion -> ()
    seqCo (Refl Type
    ty)                 = Type -> ()
    seqType Type
    ty
    seqCo (GRefl Role
    r Type
    ty MCoercion
    mco)          = Role
    r Role -> () -> ()
    forall a b. a -> b -> b
    `seq` Type -> ()
    seqType Type
    ty () -> () -> ()
    forall a b. a -> b -> b
    `seq` MCoercion -> ()
    seqMCo MCoercion
    mco
    seqCo (TyConAppCo Role
    r TyCon
    tc [Coercion]
    cos)     = Role
    r Role -> () -> ()
    forall a b. a -> b -> b
    `seq` TyCon
    tc TyCon -> () -> ()
    forall a b. a -> b -> b
    `seq` [Coercion] -> ()
    seqCos [Coercion]
    cos
    seqCo (AppCo Coercion
    co1 Coercion
    co2)           = Coercion -> ()
    seqCo Coercion
    co1 () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co2
    seqCo (ForAllCo CoVar
    tv Coercion
    k Coercion
    co)        = Type -> ()
    seqType (CoVar -> Type
    varType CoVar
    tv) () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    k
                                                           () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co
    seqCo (FunCo Role
    r FunTyFlag
    af1 FunTyFlag
    af2 Coercion
    w Coercion
    co1 Coercion
    co2) = Role
    r Role -> () -> ()
    forall a b. a -> b -> b
    `seq` FunTyFlag
    af1 FunTyFlag -> () -> ()
    forall a b. a -> b -> b
    `seq` FunTyFlag
    af2 FunTyFlag -> () -> ()
    forall a b. a -> b -> b
    `seq`
                                        Coercion -> ()
    seqCo Coercion
    w () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co1 () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co2
    seqCo (CoVarCo CoVar
    cv)              = CoVar
    cv CoVar -> () -> ()
    forall a b. a -> b -> b
    `seq` ()
    seqCo (HoleCo CoercionHole
    h)                = CoercionHole -> CoVar
    coHoleCoVar CoercionHole
    h CoVar -> () -> ()
    forall a b. a -> b -> b
    `seq` ()
    seqCo (AxiomInstCo CoAxiom Branched
    con Arity
    ind [Coercion]
    cos) = CoAxiom Branched
    con CoAxiom Branched -> () -> ()
    forall a b. a -> b -> b
    `seq` Arity
    ind Arity -> () -> ()
    forall a b. a -> b -> b
    `seq` [Coercion] -> ()
    seqCos [Coercion]
    cos
    seqCo (UnivCo UnivCoProvenance
    p Role
    r Type
    t1 Type
    t2)
      = UnivCoProvenance -> ()
    seqProv UnivCoProvenance
    p () -> () -> ()
    forall a b. a -> b -> b
    `seq` Role
    r Role -> () -> ()
    forall a b. a -> b -> b
    `seq` Type -> ()
    seqType Type
    t1 () -> () -> ()
    forall a b. a -> b -> b
    `seq` Type -> ()
    seqType Type
    t2
    seqCo (SymCo Coercion
    co)                = Coercion -> ()
    seqCo Coercion
    co
    seqCo (TransCo Coercion
    co1 Coercion
    co2)         = Coercion -> ()
    seqCo Coercion
    co1 () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co2
    seqCo (SelCo CoSel
    n Coercion
    co)              = CoSel
    n CoSel -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co
    seqCo (LRCo LeftOrRight
    lr Coercion
    co)              = LeftOrRight
    lr LeftOrRight -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    co
    seqCo (InstCo Coercion
    co Coercion
    arg)           = Coercion -> ()
    seqCo Coercion
    co () -> () -> ()
    forall a b. a -> b -> b
    `seq` Coercion -> ()
    seqCo Coercion
    arg
    seqCo (KindCo Coercion
    co)               = Coercion -> ()
    seqCo Coercion
    co
    seqCo (SubCo Coercion
    co)                = Coercion -> ()
    seqCo Coercion
    co
    seqCo (AxiomRuleCo CoAxiomRule
    _ [Coercion]
    cs)        = [Coercion] -> ()
    seqCos [Coercion]
    cs

    seqProv :: UnivCoProvenance -> ()
    seqProv :: UnivCoProvenance -> ()
    seqProv (PhantomProv Coercion
    co)    = Coercion -> ()
    seqCo Coercion
    co
    seqProv (ProofIrrelProv Coercion
    co) = Coercion -> ()
    seqCo Coercion
    co
    seqProv (PluginProv String
    _)      = ()
    seqProv (CorePrepProv Bool
    _)    = ()

    seqCos :: [Coercion] -> ()
    seqCos :: [Coercion] -> ()
    seqCos []       = ()
    seqCos (Coercion
    co:[Coercion]
    cos) = Coercion -> ()
    seqCo Coercion
    co () -> () -> ()
    forall a b. a -> b -> b
    `seq` [Coercion] -> ()
    seqCos [Coercion]
    cos

    {-
    %************************************************************************
    %*                                                                      *
                 The kind of a type, and of a coercion
    %*                                                                      *
    %************************************************************************
    -}

    -- | Apply 'coercionKind' to multiple 'Coercion's
    coercionKinds :: [Coercion] -> Pair [Type]
    coercionKinds :: [Coercion] -> Pair [Type]
    coercionKinds [Coercion]
    tys = [Pair Type] -> Pair [Type]
    forall (t :: * -> *) (f :: * -> *) a.
    (Traversable t, Applicative f) =>
    t (f a) -> f (t a)
    forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
    sequenceA ([Pair Type] -> Pair [Type]) -> [Pair Type] -> Pair [Type]
    forall a b. (a -> b) -> a -> b
    $ (Coercion -> Pair Type) -> [Coercion] -> [Pair Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Pair Type
    coercionKind [Coercion]
    tys

    -- | Get a coercion's kind and role.
    coercionKindRole :: Coercion -> (Pair Type, Role)
    coercionKindRole :: Coercion -> (Pair Type, Role)
    coercionKindRole Coercion
    co = (Coercion -> Pair Type
    coercionKind Coercion
    co, Coercion -> Role
    coercionRole Coercion
    co)

    coercionType :: Coercion -> Type
    coercionType :: Coercion -> Type
    coercionType Coercion
    co = case Coercion -> (Pair Type, Role)
    coercionKindRole Coercion
    co of
      (Pair Type
    ty1 Type
    ty2, Role
    r) -> Role -> Type -> Type -> Type
    mkCoercionType Role
    r Type
    ty1 Type
    ty2

    ------------------
    -- | If it is the case that
    --
    -- > c :: (t1 ~ t2)
    --
    -- i.e. the kind of @c@ relates @t1@ and @t2@, then @coercionKind c = Pair t1 t2@.

    coercionKind :: Coercion -> Pair Type
    coercionKind :: Coercion -> Pair Type
    coercionKind Coercion
    co = Type -> Type -> Pair Type
    forall a. a -> a -> Pair a
    Pair (Coercion -> Type
    coercionLKind Coercion
    co) (Coercion -> Type
    coercionRKind Coercion
    co)

    coercionLKind :: Coercion -> Type
    coercionLKind :: Coercion -> Type
    coercionLKind Coercion
    co
      = Coercion -> Type
    go Coercion
    co
      where
        go :: Coercion -> Type
    go (Refl Type
    ty)                 = Type
    ty
        go (GRefl Role
    _ Type
    ty MCoercion
    _)            = Type
    ty
        go (TyConAppCo Role
    _ TyCon
    tc [Coercion]
    cos)     = TyCon -> [Type] -> Type
    mkTyConApp TyCon
    tc ((Coercion -> Type) -> [Coercion] -> [Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Type
    go [Coercion]
    cos)
        go (AppCo Coercion
    co1 Coercion
    co2)           = Type -> Type -> Type
    mkAppTy (Coercion -> Type
    go Coercion
    co1) (Coercion -> Type
    go Coercion
    co2)
        go (ForAllCo CoVar
    tv1 Coercion
    _ Coercion
    co1)      = CoVar -> Type -> Type
    mkTyCoInvForAllTy CoVar
    tv1 (Coercion -> Type
    go Coercion
    co1)
        go (FunCo { fco_afl :: Coercion -> FunTyFlag
    fco_afl = FunTyFlag
    af, fco_mult :: Coercion -> Coercion
    fco_mult = Coercion
    mult, fco_arg :: Coercion -> Coercion
    fco_arg = Coercion
    arg, fco_res :: Coercion -> Coercion
    fco_res = Coercion
    res})
           {- See Note [FunCo] -}    = FunTy { ft_af :: FunTyFlag
    ft_af = FunTyFlag
    af, ft_mult :: Type
    ft_mult = Coercion -> Type
    go Coercion
    mult
                                             , ft_arg :: Type
    ft_arg = Coercion -> Type
    go Coercion
    arg, ft_res :: Type
    ft_res = Coercion -> Type
    go Coercion
    res }
        go (CoVarCo CoVar
    cv)              = (() :: Constraint) => CoVar -> Type
    CoVar -> Type
    coVarLType CoVar
    cv
        go (HoleCo CoercionHole
    h)                = (() :: Constraint) => CoVar -> Type
    CoVar -> Type
    coVarLType (CoercionHole -> CoVar
    coHoleCoVar CoercionHole
    h)
        go (UnivCo UnivCoProvenance
    _ Role
    _ Type
    ty1 Type
    _)        = Type
    ty1
        go (SymCo Coercion
    co)                = Coercion -> Type
    coercionRKind Coercion
    co
        go (TransCo Coercion
    co1 Coercion
    _)           = Coercion -> Type
    go Coercion
    co1
        go (LRCo LeftOrRight
    lr Coercion
    co)              = LeftOrRight -> (Type, Type) -> Type
    forall a. LeftOrRight -> (a, a) -> a
    pickLR LeftOrRight
    lr (Type -> (Type, Type)
    splitAppTy (Coercion -> Type
    go Coercion
    co))
        go (InstCo Coercion
    aco Coercion
    arg)          = Coercion -> [Type] -> Type
    go_app Coercion
    aco [Coercion -> Type
    go Coercion
    arg]
        go (KindCo Coercion
    co)               = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind (Coercion -> Type
    go Coercion
    co)
        go (SubCo Coercion
    co)                = Coercion -> Type
    go Coercion
    co
        go (SelCo CoSel
    d Coercion
    co)              = (() :: Constraint) => CoSel -> Type -> Type
    CoSel -> Type -> Type
    getNthFromType CoSel
    d (Coercion -> Type
    go Coercion
    co)
        go (AxiomInstCo CoAxiom Branched
    ax Arity
    ind [Coercion]
    cos)  = CoAxiom Branched -> Arity -> [Type] -> Type
    forall {br :: BranchFlag}. CoAxiom br -> Arity -> [Type] -> Type
    go_ax_inst CoAxiom Branched
    ax Arity
    ind ((Coercion -> Type) -> [Coercion] -> [Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Type
    go [Coercion]
    cos)
        go (AxiomRuleCo CoAxiomRule
    ax [Coercion]
    cos)      = Pair Type -> Type
    forall a. Pair a -> a
    pFst (Pair Type -> Type) -> Pair Type -> Type
    forall a b. (a -> b) -> a -> b
    $ String -> Maybe (Pair Type) -> Pair Type
    forall a. HasCallStack => String -> Maybe a -> a
    expectJust String
    "coercionKind" (Maybe (Pair Type) -> Pair Type) -> Maybe (Pair Type) -> Pair Type
    forall a b. (a -> b) -> a -> b
    $
                                       CoAxiomRule -> [Pair Type] -> Maybe (Pair Type)
    coaxrProves CoAxiomRule
    ax ([Pair Type] -> Maybe (Pair Type))
    -> [Pair Type] -> Maybe (Pair Type)
    forall a b. (a -> b) -> a -> b
    $ (Coercion -> Pair Type) -> [Coercion] -> [Pair Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Pair Type
    coercionKind [Coercion]
    cos

        go_ax_inst :: CoAxiom br -> Arity -> [Type] -> Type
    go_ax_inst CoAxiom br
    ax Arity
    ind [Type]
    tys
          | CoAxBranch { cab_tvs :: CoAxBranch -> [CoVar]
    cab_tvs = [CoVar]
    tvs, cab_cvs :: CoAxBranch -> [CoVar]
    cab_cvs = [CoVar]
    cvs
                       , cab_lhs :: CoAxBranch -> [Type]
    cab_lhs = [Type]
    lhs } <- CoAxiom br -> Arity -> CoAxBranch
    forall (br :: BranchFlag). CoAxiom br -> Arity -> CoAxBranch
    coAxiomNthBranch CoAxiom br
    ax Arity
    ind
          , let ([Type]
    tys1, [Type]
    cotys1) = [CoVar] -> [Type] -> ([Type], [Type])
    forall b a. [b] -> [a] -> ([a], [a])
    splitAtList [CoVar]
    tvs [Type]
    tys
                cos1 :: [Coercion]
    cos1           = (Type -> Coercion) -> [Type] -> [Coercion]
    forall a b. (a -> b) -> [a] -> [b]
    map Type -> Coercion
    stripCoercionTy [Type]
    cotys1
          = Bool -> Type -> Type
    forall a. HasCallStack => Bool -> a -> a
    assert ([Type]
    tys [Type] -> [CoVar] -> Bool
    forall a b. [a] -> [b] -> Bool
    `equalLength` ([CoVar]
    tvs [CoVar] -> [CoVar] -> [CoVar]
    forall a. [a] -> [a] -> [a]
    ++ [CoVar]
    cvs)) (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
                      -- Invariant of AxiomInstCo: cos should
                      -- exactly saturate the axiom branch
            [CoVar] -> [Type] -> Type -> Type
    (() :: Constraint) => [CoVar] -> [Type] -> Type -> Type
    substTyWith [CoVar]
    tvs [Type]
    tys1       (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
            [CoVar] -> [Coercion] -> Type -> Type
    substTyWithCoVars [CoVar]
    cvs [Coercion]
    cos1 (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
            TyCon -> [Type] -> Type
    mkTyConApp (CoAxiom br -> TyCon
    forall (br :: BranchFlag). CoAxiom br -> TyCon
    coAxiomTyCon CoAxiom br
    ax) [Type]
    lhs

        go_app :: Coercion -> [Type] -> Type
        -- Collect up all the arguments and apply all at once
        -- See Note [Nested InstCos]
        go_app :: Coercion -> [Type] -> Type
    go_app (InstCo Coercion
    co Coercion
    arg) [Type]
    args = Coercion -> [Type] -> Type
    go_app Coercion
    co (Coercion -> Type
    go Coercion
    argType -> [Type] -> [Type]
    forall a. a -> [a] -> [a]
    :[Type]
    args)
        go_app Coercion
    co              [Type]
    args = (() :: Constraint) => Type -> [Type] -> Type
    Type -> [Type] -> Type
    piResultTys (Coercion -> Type
    go Coercion
    co) [Type]
    args

    getNthFromType :: HasDebugCallStack => CoSel -> Type -> Type
    getNthFromType :: (() :: Constraint) => CoSel -> Type -> Type
    getNthFromType (SelFun FunSel
    fs) Type
    ty
      | Just (FunTyFlag
    _af, Type
    mult, Type
    arg, Type
    res) <- Type -> Maybe (FunTyFlag, Type, Type, Type)
    splitFunTy_maybe Type
    ty
      = FunSel -> Type -> Type -> Type -> Type
    forall a. FunSel -> a -> a -> a -> a
    getNthFun FunSel
    fs Type
    mult Type
    arg Type
    res

    getNthFromType (SelTyCon Arity
    n Role
    _) Type
    ty
      | Just [Type]
    args <- Type -> Maybe [Type]
    tyConAppArgs_maybe Type
    ty
      = Bool -> SDoc -> Type -> Type
    forall a. HasCallStack => Bool -> SDoc -> a -> a
    assertPpr ([Type]
    args [Type] -> Arity -> Bool
    forall a. [a] -> Arity -> Bool
    `lengthExceeds` Arity
    n) (Arity -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Arity
    n SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty) (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
        [Type]
    args [Type] -> Arity -> Type
    forall a. Outputable a => [a] -> Arity -> a
    `getNth` Arity
    n

    getNthFromType CoSel
    SelForAll Type
    ty       -- Works for both tyvar and covar
      | Just (CoVar
    tv,Type
    _) <- Type -> Maybe (CoVar, Type)
    splitForAllTyCoVar_maybe Type
    ty
      = CoVar -> Type
    tyVarKind CoVar
    tv

    getNthFromType CoSel
    cs Type
    ty
      = String -> SDoc -> Type
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "getNthFromType" (CoSel -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoSel
    cs SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty)

    coercionRKind :: Coercion -> Type
    coercionRKind :: Coercion -> Type
    coercionRKind Coercion
    co
      = Coercion -> Type
    go Coercion
    co
      where
        go :: Coercion -> Type
    go (Refl Type
    ty)                 = Type
    ty
        go (GRefl Role
    _ Type
    ty MCoercion
    MRefl)        = Type
    ty
        go (GRefl Role
    _ Type
    ty (MCo Coercion
    co1))    = Type -> Coercion -> Type
    mkCastTy Type
    ty Coercion
    co1
        go (TyConAppCo Role
    _ TyCon
    tc [Coercion]
    cos)     = TyCon -> [Type] -> Type
    mkTyConApp TyCon
    tc ((Coercion -> Type) -> [Coercion] -> [Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Type
    go [Coercion]
    cos)
        go (AppCo Coercion
    co1 Coercion
    co2)           = Type -> Type -> Type
    mkAppTy (Coercion -> Type
    go Coercion
    co1) (Coercion -> Type
    go Coercion
    co2)
        go (CoVarCo CoVar
    cv)              = (() :: Constraint) => CoVar -> Type
    CoVar -> Type
    coVarRType CoVar
    cv
        go (HoleCo CoercionHole
    h)                = (() :: Constraint) => CoVar -> Type
    CoVar -> Type
    coVarRType (CoercionHole -> CoVar
    coHoleCoVar CoercionHole
    h)
        go (FunCo { fco_afr :: Coercion -> FunTyFlag
    fco_afr = FunTyFlag
    af, fco_mult :: Coercion -> Coercion
    fco_mult = Coercion
    mult, fco_arg :: Coercion -> Coercion
    fco_arg = Coercion
    arg, fco_res :: Coercion -> Coercion
    fco_res = Coercion
    res})
           {- See Note [FunCo] -}    = FunTy { ft_af :: FunTyFlag
    ft_af = FunTyFlag
    af, ft_mult :: Type
    ft_mult = Coercion -> Type
    go Coercion
    mult
                                             , ft_arg :: Type
    ft_arg = Coercion -> Type
    go Coercion
    arg, ft_res :: Type
    ft_res = Coercion -> Type
    go Coercion
    res }
        go (UnivCo UnivCoProvenance
    _ Role
    _ Type
    _ Type
    ty2)        = Type
    ty2
        go (SymCo Coercion
    co)                = Coercion -> Type
    coercionLKind Coercion
    co
        go (TransCo Coercion
    _ Coercion
    co2)           = Coercion -> Type
    go Coercion
    co2
        go (LRCo LeftOrRight
    lr Coercion
    co)              = LeftOrRight -> (Type, Type) -> Type
    forall a. LeftOrRight -> (a, a) -> a
    pickLR LeftOrRight
    lr (Type -> (Type, Type)
    splitAppTy (Coercion -> Type
    go Coercion
    co))
        go (InstCo Coercion
    aco Coercion
    arg)          = Coercion -> [Type] -> Type
    go_app Coercion
    aco [Coercion -> Type
    go Coercion
    arg]
        go (KindCo Coercion
    co)               = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind (Coercion -> Type
    go Coercion
    co)
        go (SubCo Coercion
    co)                = Coercion -> Type
    go Coercion
    co
        go (SelCo CoSel
    d Coercion
    co)              = (() :: Constraint) => CoSel -> Type -> Type
    CoSel -> Type -> Type
    getNthFromType CoSel
    d (Coercion -> Type
    go Coercion
    co)
        go (AxiomInstCo CoAxiom Branched
    ax Arity
    ind [Coercion]
    cos)  = CoAxiom Branched -> Arity -> [Type] -> Type
    forall {br :: BranchFlag}. CoAxiom br -> Arity -> [Type] -> Type
    go_ax_inst CoAxiom Branched
    ax Arity
    ind ((Coercion -> Type) -> [Coercion] -> [Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Type
    go [Coercion]
    cos)
        go (AxiomRuleCo CoAxiomRule
    ax [Coercion]
    cos)      = Pair Type -> Type
    forall a. Pair a -> a
    pSnd (Pair Type -> Type) -> Pair Type -> Type
    forall a b. (a -> b) -> a -> b
    $ String -> Maybe (Pair Type) -> Pair Type
    forall a. HasCallStack => String -> Maybe a -> a
    expectJust String
    "coercionKind" (Maybe (Pair Type) -> Pair Type) -> Maybe (Pair Type) -> Pair Type
    forall a b. (a -> b) -> a -> b
    $
                                       CoAxiomRule -> [Pair Type] -> Maybe (Pair Type)
    coaxrProves CoAxiomRule
    ax ([Pair Type] -> Maybe (Pair Type))
    -> [Pair Type] -> Maybe (Pair Type)
    forall a b. (a -> b) -> a -> b
    $ (Coercion -> Pair Type) -> [Coercion] -> [Pair Type]
    forall a b. (a -> b) -> [a] -> [b]
    map Coercion -> Pair Type
    coercionKind [Coercion]
    cos

        go co :: Coercion
    co@(ForAllCo CoVar
    tv1 Coercion
    k_co Coercion
    co1) -- works for both tyvar and covar
           | Coercion -> Bool
    isGReflCo Coercion
    k_co           = CoVar -> Type -> Type
    mkTyCoInvForAllTy CoVar
    tv1 (Coercion -> Type
    go Coercion
    co1)
             -- kind_co always has kind @Type@, thus @isGReflCo@
           | Bool
    otherwise                = Subst -> Coercion -> Type
    go_forall Subst
    empty_subst Coercion
    co
           where
             empty_subst :: Subst
    empty_subst = InScopeSet -> Subst
    mkEmptySubst (VarSet -> InScopeSet
    mkInScopeSet (VarSet -> InScopeSet) -> VarSet -> InScopeSet
    forall a b. (a -> b) -> a -> b
    $ Coercion -> VarSet
    tyCoVarsOfCo Coercion
    co)

        go_ax_inst :: CoAxiom br -> Arity -> [Type] -> Type
    go_ax_inst CoAxiom br
    ax Arity
    ind [Type]
    tys
          | CoAxBranch { cab_tvs :: CoAxBranch -> [CoVar]
    cab_tvs = [CoVar]
    tvs, cab_cvs :: CoAxBranch -> [CoVar]
    cab_cvs = [CoVar]
    cvs
                       , cab_rhs :: CoAxBranch -> Type
    cab_rhs = Type
    rhs } <- CoAxiom br -> Arity -> CoAxBranch
    forall (br :: BranchFlag). CoAxiom br -> Arity -> CoAxBranch
    coAxiomNthBranch CoAxiom br
    ax Arity
    ind
          , let ([Type]
    tys2, [Type]
    cotys2) = [CoVar] -> [Type] -> ([Type], [Type])
    forall b a. [b] -> [a] -> ([a], [a])
    splitAtList [CoVar]
    tvs [Type]
    tys
                cos2 :: [Coercion]
    cos2           = (Type -> Coercion) -> [Type] -> [Coercion]
    forall a b. (a -> b) -> [a] -> [b]
    map Type -> Coercion
    stripCoercionTy [Type]
    cotys2
          = Bool -> Type -> Type
    forall a. HasCallStack => Bool -> a -> a
    assert ([Type]
    tys [Type] -> [CoVar] -> Bool
    forall a b. [a] -> [b] -> Bool
    `equalLength` ([CoVar]
    tvs [CoVar] -> [CoVar] -> [CoVar]
    forall a. [a] -> [a] -> [a]
    ++ [CoVar]
    cvs)) (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
                      -- Invariant of AxiomInstCo: cos should
                      -- exactly saturate the axiom branch
            [CoVar] -> [Type] -> Type -> Type
    (() :: Constraint) => [CoVar] -> [Type] -> Type -> Type
    substTyWith [CoVar]
    tvs [Type]
    tys2 (Type -> Type) -> Type -> Type
    forall a b. (a -> b) -> a -> b
    $
            [CoVar] -> [Coercion] -> Type -> Type
    substTyWithCoVars [CoVar]
    cvs [Coercion]
    cos2 Type
    rhs

        go_app :: Coercion -> [Type] -> Type
        -- Collect up all the arguments and apply all at once
        -- See Note [Nested InstCos]
        go_app :: Coercion -> [Type] -> Type
    go_app (InstCo Coercion
    co Coercion
    arg) [Type]
    args = Coercion -> [Type] -> Type
    go_app Coercion
    co (Coercion -> Type
    go Coercion
    argType -> [Type] -> [Type]
    forall a. a -> [a] -> [a]
    :[Type]
    args)
        go_app Coercion
    co              [Type]
    args = (() :: Constraint) => Type -> [Type] -> Type
    Type -> [Type] -> Type
    piResultTys (Coercion -> Type
    go Coercion
    co) [Type]
    args

        go_forall :: Subst -> Coercion -> Type
    go_forall Subst
    subst (ForAllCo CoVar
    tv1 Coercion
    k_co Coercion
    co)
          -- See Note [Nested ForAllCos]
          | CoVar -> Bool
    isTyVar CoVar
    tv1
          = CoVar -> Type -> Type
    mkInfForAllTy CoVar
    tv2 (Subst -> Coercion -> Type
    go_forall Subst
    subst' Coercion
    co)
          where
            k2 :: Type
    k2  = Coercion -> Type
    coercionRKind Coercion
    k_co
            tv2 :: CoVar
    tv2 = CoVar -> Type -> CoVar
    setTyVarKind CoVar
    tv1 ((() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy Subst
    subst Type
    k2)
            subst' :: Subst
    subst' | Coercion -> Bool
    isGReflCo Coercion
    k_co = Subst -> CoVar -> Subst
    extendSubstInScope Subst
    subst CoVar
    tv1
                     -- kind_co always has kind @Type@, thus @isGReflCo@
                   | Bool
    otherwise      = Subst -> CoVar -> Type -> Subst
    extendTvSubst (Subst -> CoVar -> Subst
    extendSubstInScope Subst
    subst CoVar
    tv2) CoVar
    tv1 (Type -> Subst) -> Type -> Subst
    forall a b. (a -> b) -> a -> b
    $
                                      CoVar -> Type
    TyVarTy CoVar
    tv2 Type -> Coercion -> Type
    `mkCastTy` Coercion -> Coercion
    mkSymCo Coercion
    k_co

        go_forall Subst
    subst (ForAllCo CoVar
    cv1 Coercion
    k_co Coercion
    co)
          | CoVar -> Bool
    isCoVar CoVar
    cv1
          = CoVar -> Type -> Type
    mkTyCoInvForAllTy CoVar
    cv2 (Subst -> Coercion -> Type
    go_forall Subst
    subst' Coercion
    co)
          where
            k2 :: Type
    k2    = Coercion -> Type
    coercionRKind Coercion
    k_co
            r :: Role
    r     = CoVar -> Role
    coVarRole CoVar
    cv1
            k_co' :: Coercion
    k_co' = Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    r Role
    Nominal Coercion
    k_co
            eta1 :: Coercion
    eta1  = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    2 Role
    r) Coercion
    k_co'
            eta2 :: Coercion
    eta2  = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    3 Role
    r) Coercion
    k_co'

            -- k_co :: (t1 ~r t2) ~N (s1 ~r s2)
            -- k1    = t1 ~r t2
            -- k2    = s1 ~r s2
            -- cv1  :: t1 ~r t2
            -- cv2  :: s1 ~r s2
            -- eta1 :: t1 ~r s1
            -- eta2 :: t2 ~r s2
            -- n_subst  = (eta1 ; cv2 ; sym eta2) :: t1 ~r t2

            cv2 :: CoVar
    cv2     = CoVar -> Type -> CoVar
    setVarType CoVar
    cv1 ((() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy Subst
    subst Type
    k2)
            n_subst :: Coercion
    n_subst = Coercion
    eta1 Coercion -> Coercion -> Coercion
    `mkTransCo` (CoVar -> Coercion
    mkCoVarCo CoVar
    cv2) Coercion -> Coercion -> Coercion
    `mkTransCo` (Coercion -> Coercion
    mkSymCo Coercion
    eta2)
            subst' :: Subst
    subst'  | Coercion -> Bool
    isReflCo Coercion
    k_co = Subst -> CoVar -> Subst
    extendSubstInScope Subst
    subst CoVar
    cv1
                    | Bool
    otherwise     = Subst -> CoVar -> Coercion -> Subst
    extendCvSubst (Subst -> CoVar -> Subst
    extendSubstInScope Subst
    subst CoVar
    cv2)
                                                    CoVar
    cv1 Coercion
    n_subst

        go_forall Subst
    subst Coercion
    other_co
          -- when other_co is not a ForAllCo
          = (() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy Subst
    subst (Coercion -> Type
    go Coercion
    other_co)

    {-

    Note [Nested ForAllCos]
    ~~~~~~~~~~~~~~~~~~~~~~~

    Suppose we need `coercionKind (ForAllCo a1 (ForAllCo a2 ... (ForAllCo an
    co)...) )`.   We do not want to perform `n` single-type-variable
    substitutions over the kind of `co`; rather we want to do one substitution
    which substitutes for all of `a1`, `a2` ... simultaneously.  If we do one
    at a time we get the performance hole reported in #11735.

    Solution: gather up the type variables for nested `ForAllCos`, and
    substitute for them all at once.  Remarkably, for #11735 this single
    change reduces /total/ compile time by a factor of more than ten.

    -}

    -- | Retrieve the role from a coercion.
    coercionRole :: Coercion -> Role
    coercionRole :: Coercion -> Role
    coercionRole = Coercion -> Role
    go
      where
        go :: Coercion -> Role
    go (Refl Type
    _) = Role
    Nominal
        go (GRefl Role
    r Type
    _ MCoercion
    _) = Role
    r
        go (TyConAppCo Role
    r TyCon
    _ [Coercion]
    _) = Role
    r
        go (AppCo Coercion
    co1 Coercion
    _) = Coercion -> Role
    go Coercion
    co1
        go (ForAllCo CoVar
    _ Coercion
    _ Coercion
    co) = Coercion -> Role
    go Coercion
    co
        go (FunCo { fco_role :: Coercion -> Role
    fco_role = Role
    r }) = Role
    r
        go (CoVarCo CoVar
    cv) = CoVar -> Role
    coVarRole CoVar
    cv
        go (HoleCo CoercionHole
    h)   = CoVar -> Role
    coVarRole (CoercionHole -> CoVar
    coHoleCoVar CoercionHole
    h)
        go (AxiomInstCo CoAxiom Branched
    ax Arity
    _ [Coercion]
    _) = CoAxiom Branched -> Role
    forall (br :: BranchFlag). CoAxiom br -> Role
    coAxiomRole CoAxiom Branched
    ax
        go (UnivCo UnivCoProvenance
    _ Role
    r Type
    _ Type
    _)  = Role
    r
        go (SymCo Coercion
    co) = Coercion -> Role
    go Coercion
    co
        go (TransCo Coercion
    co1 Coercion
    _co2) = Coercion -> Role
    go Coercion
    co1
        go (SelCo CoSel
    SelForAll      Coercion
    _co) = Role
    Nominal
        go (SelCo (SelTyCon Arity
    _ Role
    r) Coercion
    _co) = Role
    r
        go (SelCo (SelFun FunSel
    fs)     Coercion
    co) = Role -> FunSel -> Role
    funRole (Coercion -> Role
    coercionRole Coercion
    co) FunSel
    fs
        go (LRCo {}) = Role
    Nominal
        go (InstCo Coercion
    co Coercion
    _) = Coercion -> Role
    go Coercion
    co
        go (KindCo {}) = Role
    Nominal
        go (SubCo Coercion
    _) = Role
    Representational
        go (AxiomRuleCo CoAxiomRule
    ax [Coercion]
    _) = CoAxiomRule -> Role
    coaxrRole CoAxiomRule
    ax

    {-
    Note [Nested InstCos]
    ~~~~~~~~~~~~~~~~~~~~~
    In #5631 we found that 70% of the entire compilation time was
    being spent in coercionKind!  The reason was that we had
       (g @ ty1 @ ty2 .. @ ty100)    -- The "@s" are InstCos
    where
       g :: forall a1 a2 .. a100. phi
    If we deal with the InstCos one at a time, we'll do this:
       1.  Find the kind of (g @ ty1 .. @ ty99) : forall a100. phi'
       2.  Substitute phi'[ ty100/a100 ], a single tyvar->type subst
    But this is a *quadratic* algorithm, and the blew up #5631.
    So it's very important to do the substitution simultaneously;
    cf Type.piResultTys (which in fact we call here).

    -}

    -- | Makes a coercion type from two types: the types whose equality
    -- is proven by the relevant 'Coercion'
    mkCoercionType :: Role -> Type -> Type -> Type
    mkCoercionType :: Role -> Type -> Type -> Type
    mkCoercionType Role
    Nominal          = Type -> Type -> Type
    mkPrimEqPred
    mkCoercionType Role
    Representational = Type -> Type -> Type
    mkReprPrimEqPred
    mkCoercionType Role
    Phantom          = \Type
    ty1 Type
    ty2 ->
      let ki1 :: Type
    ki1 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty1
          ki2 :: Type
    ki2 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty2
      in
      TyCon -> [Type] -> Type
    TyConApp TyCon
    eqPhantPrimTyCon [Type
    ki1, Type
    ki2, Type
    ty1, Type
    ty2]

    -- | Creates a primitive type equality predicate.
    -- Invariant: the types are not Coercions
    mkPrimEqPred :: Type -> Type -> Type
    mkPrimEqPred :: Type -> Type -> Type
    mkPrimEqPred Type
    ty1 Type
    ty2
      = TyCon -> [Type] -> Type
    mkTyConApp TyCon
    eqPrimTyCon [Type
    k1, Type
    k2, Type
    ty1, Type
    ty2]
      where
        k1 :: Type
    k1 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty1
        k2 :: Type
    k2 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty2

    -- | Makes a lifted equality predicate at the given role
    mkPrimEqPredRole :: Role -> Type -> Type -> PredType
    mkPrimEqPredRole :: Role -> Type -> Type -> Type
    mkPrimEqPredRole Role
    Nominal          = Type -> Type -> Type
    mkPrimEqPred
    mkPrimEqPredRole Role
    Representational = Type -> Type -> Type
    mkReprPrimEqPred
    mkPrimEqPredRole Role
    Phantom          = String -> Type -> Type -> Type
    forall a. HasCallStack => String -> a
    panic String
    "mkPrimEqPredRole phantom"

    -- | Creates a primitive type equality predicate with explicit kinds
    mkHeteroPrimEqPred :: Kind -> Kind -> Type -> Type -> Type
    mkHeteroPrimEqPred :: Type -> Type -> Type -> Type -> Type
    mkHeteroPrimEqPred Type
    k1 Type
    k2 Type
    ty1 Type
    ty2 = TyCon -> [Type] -> Type
    mkTyConApp TyCon
    eqPrimTyCon [Type
    k1, Type
    k2, Type
    ty1, Type
    ty2]

    -- | Creates a primitive representational type equality predicate
    -- with explicit kinds
    mkHeteroReprPrimEqPred :: Kind -> Kind -> Type -> Type -> Type
    mkHeteroReprPrimEqPred :: Type -> Type -> Type -> Type -> Type
    mkHeteroReprPrimEqPred Type
    k1 Type
    k2 Type
    ty1 Type
    ty2
      = TyCon -> [Type] -> Type
    mkTyConApp TyCon
    eqReprPrimTyCon [Type
    k1, Type
    k2, Type
    ty1, Type
    ty2]

    mkReprPrimEqPred :: Type -> Type -> Type
    mkReprPrimEqPred :: Type -> Type -> Type
    mkReprPrimEqPred Type
    ty1  Type
    ty2
      = TyCon -> [Type] -> Type
    mkTyConApp TyCon
    eqReprPrimTyCon [Type
    k1, Type
    k2, Type
    ty1, Type
    ty2]
      where
        k1 :: Type
    k1 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty1
        k2 :: Type
    k2 = (() :: Constraint) => Type -> Type
    Type -> Type
    typeKind Type
    ty2

    -- | Assuming that two types are the same, ignoring coercions, find
    -- a nominal coercion between the types. This is useful when optimizing
    -- transitivity over coercion applications, where splitting two
    -- AppCos might yield different kinds. See Note [EtaAppCo] in
    -- "GHC.Core.Coercion.Opt".
    buildCoercion :: Type -> Type -> CoercionN
    buildCoercion :: Type -> Type -> Coercion
    buildCoercion Type
    orig_ty1 Type
    orig_ty2 = Type -> Type -> Coercion
    go Type
    orig_ty1 Type
    orig_ty2
      where
        go :: Type -> Type -> Coercion
    go Type
    ty1 Type
    ty2 | Just Type
    ty1' <- Type -> Maybe Type
    coreView Type
    ty1 = Type -> Type -> Coercion
    go Type
    ty1' Type
    ty2
                   | Just Type
    ty2' <- Type -> Maybe Type
    coreView Type
    ty2 = Type -> Type -> Coercion
    go Type
    ty1 Type
    ty2'

        go (CastTy Type
    ty1 Coercion
    co) Type
    ty2
          = let co' :: Coercion
    co' = Type -> Type -> Coercion
    go Type
    ty1 Type
    ty2
                r :: Role
    r = Coercion -> Role
    coercionRole Coercion
    co'
            in  Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceLeftCo Role
    r Type
    ty1 Coercion
    co Coercion
    co'

        go Type
    ty1 (CastTy Type
    ty2 Coercion
    co)
          = let co' :: Coercion
    co' = Type -> Type -> Coercion
    go Type
    ty1 Type
    ty2
                r :: Role
    r = Coercion -> Role
    coercionRole Coercion
    co'
            in  Role -> Type -> Coercion -> Coercion -> Coercion
    mkCoherenceRightCo Role
    r Type
    ty2 Coercion
    co Coercion
    co'

        go ty1 :: Type
    ty1@(TyVarTy CoVar
    tv1) Type
    _tyvarty
          = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (case Type
    _tyvarty of
                      { TyVarTy CoVar
    tv2 -> CoVar
    tv1 CoVar -> CoVar -> Bool
    forall a. Eq a => a -> a -> Bool
    == CoVar
    tv2
                      ; Type
    _           -> Bool
    False      }) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
            Type -> Coercion
    mkNomReflCo Type
    ty1

        go (FunTy { ft_af :: Type -> FunTyFlag
    ft_af = FunTyFlag
    af1, ft_mult :: Type -> Type
    ft_mult = Type
    w1, ft_arg :: Type -> Type
    ft_arg = Type
    arg1, ft_res :: Type -> Type
    ft_res = Type
    res1 })
           (FunTy { ft_af :: Type -> FunTyFlag
    ft_af = FunTyFlag
    af2, ft_mult :: Type -> Type
    ft_mult = Type
    w2, ft_arg :: Type -> Type
    ft_arg = Type
    arg2, ft_res :: Type -> Type
    ft_res = Type
    res2 })
          = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (FunTyFlag
    af1 FunTyFlag -> FunTyFlag -> Bool
    forall a. Eq a => a -> a -> Bool
    == FunTyFlag
    af2) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
            (() :: Constraint) =>
    Role -> FunTyFlag -> Coercion -> Coercion -> Coercion -> Coercion
    Role -> FunTyFlag -> Coercion -> Coercion -> Coercion -> Coercion
    mkFunCo1 Role
    Nominal FunTyFlag
    af1 (Type -> Type -> Coercion
    go Type
    w1 Type
    w2) (Type -> Type -> Coercion
    go Type
    arg1 Type
    arg2) (Type -> Type -> Coercion
    go Type
    res1 Type
    res2)

        go (TyConApp TyCon
    tc1 [Type]
    args1) (TyConApp TyCon
    tc2 [Type]
    args2)
          = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (TyCon
    tc1 TyCon -> TyCon -> Bool
    forall a. Eq a => a -> a -> Bool
    == TyCon
    tc2) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
            (() :: Constraint) => Role -> TyCon -> [Coercion] -> Coercion
    Role -> TyCon -> [Coercion] -> Coercion
    mkTyConAppCo Role
    Nominal TyCon
    tc1 ((Type -> Type -> Coercion) -> [Type] -> [Type] -> [Coercion]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Type -> Type -> Coercion
    go [Type]
    args1 [Type]
    args2)

        go (AppTy Type
    ty1a Type
    ty1b) Type
    ty2
          | Just (Type
    ty2a, Type
    ty2b) <- (() :: Constraint) => Type -> Maybe (Type, Type)
    Type -> Maybe (Type, Type)
    splitAppTyNoView_maybe Type
    ty2
          = Coercion -> Coercion -> Coercion
    mkAppCo (Type -> Type -> Coercion
    go Type
    ty1a Type
    ty2a) (Type -> Type -> Coercion
    go Type
    ty1b Type
    ty2b)

        go Type
    ty1 (AppTy Type
    ty2a Type
    ty2b)
          | Just (Type
    ty1a, Type
    ty1b) <- (() :: Constraint) => Type -> Maybe (Type, Type)
    Type -> Maybe (Type, Type)
    splitAppTyNoView_maybe Type
    ty1
          = Coercion -> Coercion -> Coercion
    mkAppCo (Type -> Type -> Coercion
    go Type
    ty1a Type
    ty2a) (Type -> Type -> Coercion
    go Type
    ty1b Type
    ty2b)

        go (ForAllTy (Bndr CoVar
    tv1 ForAllTyFlag
    _flag1) Type
    ty1) (ForAllTy (Bndr CoVar
    tv2 ForAllTyFlag
    _flag2) Type
    ty2)
          | CoVar -> Bool
    isTyVar CoVar
    tv1
          = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isTyVar CoVar
    tv2) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
            CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo CoVar
    tv1 Coercion
    kind_co (Type -> Type -> Coercion
    go Type
    ty1 Type
    ty2')
          where kind_co :: Coercion
    kind_co  = Type -> Type -> Coercion
    go (CoVar -> Type
    tyVarKind CoVar
    tv1) (CoVar -> Type
    tyVarKind CoVar
    tv2)
                in_scope :: InScopeSet
    in_scope = VarSet -> InScopeSet
    mkInScopeSet (VarSet -> InScopeSet) -> VarSet -> InScopeSet
    forall a b. (a -> b) -> a -> b
    $ Type -> VarSet
    tyCoVarsOfType Type
    ty2 VarSet -> VarSet -> VarSet
    `unionVarSet` Coercion -> VarSet
    tyCoVarsOfCo Coercion
    kind_co
                ty2' :: Type
    ty2'     = InScopeSet -> [CoVar] -> [Type] -> Type -> Type
    substTyWithInScope InScopeSet
    in_scope [CoVar
    tv2]
                             [CoVar -> Type
    mkTyVarTy CoVar
    tv1 Type -> Coercion -> Type
    `mkCastTy` Coercion
    kind_co]
                             Type
    ty2

        go (ForAllTy (Bndr CoVar
    cv1 ForAllTyFlag
    _flag1) Type
    ty1) (ForAllTy (Bndr CoVar
    cv2 ForAllTyFlag
    _flag2) Type
    ty2)
          = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (CoVar -> Bool
    isCoVar CoVar
    cv1 Bool -> Bool -> Bool
    && CoVar -> Bool
    isCoVar CoVar
    cv2) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
            CoVar -> Coercion -> Coercion -> Coercion
    mkForAllCo CoVar
    cv1 Coercion
    kind_co (Type -> Type -> Coercion
    go Type
    ty1 Type
    ty2')
          where s1 :: Type
    s1 = CoVar -> Type
    varType CoVar
    cv1
                s2 :: Type
    s2 = CoVar -> Type
    varType CoVar
    cv2
                kind_co :: Coercion
    kind_co = Type -> Type -> Coercion
    go Type
    s1 Type
    s2

                -- s1 = t1 ~r t2
                -- s2 = t3 ~r t4
                -- kind_co :: (t1 ~r t2) ~N (t3 ~r t4)
                -- eta1 :: t1 ~r t3
                -- eta2 :: t2 ~r t4

                r :: Role
    r    = CoVar -> Role
    coVarRole CoVar
    cv1
                kind_co' :: Coercion
    kind_co' = Role -> Role -> Coercion -> Coercion
    downgradeRole Role
    r Role
    Nominal Coercion
    kind_co
                eta1 :: Coercion
    eta1 = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    2 Role
    r) Coercion
    kind_co'
                eta2 :: Coercion
    eta2 = (() :: Constraint) => CoSel -> Coercion -> Coercion
    CoSel -> Coercion -> Coercion
    mkSelCo (Arity -> Role -> CoSel
    SelTyCon Arity
    3 Role
    r) Coercion
    kind_co'

                subst :: Subst
    subst = InScopeSet -> Subst
    mkEmptySubst (InScopeSet -> Subst) -> InScopeSet -> Subst
    forall a b. (a -> b) -> a -> b
    $ VarSet -> InScopeSet
    mkInScopeSet (VarSet -> InScopeSet) -> VarSet -> InScopeSet
    forall a b. (a -> b) -> a -> b
    $
                          Type -> VarSet
    tyCoVarsOfType Type
    ty2 VarSet -> VarSet -> VarSet
    `unionVarSet` Coercion -> VarSet
    tyCoVarsOfCo Coercion
    kind_co
                ty2' :: Type
    ty2'  = (() :: Constraint) => Subst -> Type -> Type
    Subst -> Type -> Type
    substTy (Subst -> CoVar -> Coercion -> Subst
    extendCvSubst Subst
    subst CoVar
    cv2 (Coercion -> Subst) -> Coercion -> Subst
    forall a b. (a -> b) -> a -> b
    $ Coercion -> Coercion
    mkSymCo Coercion
    eta1 Coercion -> Coercion -> Coercion
    `mkTransCo`
                                                           CoVar -> Coercion
    mkCoVarCo CoVar
    cv1 Coercion -> Coercion -> Coercion
    `mkTransCo`
                                                           Coercion
    eta2)
                                Type
    ty2

        go ty1 :: Type
    ty1@(LitTy TyLit
    lit1) Type
    _lit2
          = Bool -> Coercion -> Coercion
    forall a. HasCallStack => Bool -> a -> a
    assert (case Type
    _lit2 of
                      { LitTy TyLit
    lit2 -> TyLit
    lit1 TyLit -> TyLit -> Bool
    forall a. Eq a => a -> a -> Bool
    == TyLit
    lit2
                      ; Type
    _          -> Bool
    False        }) (Coercion -> Coercion) -> Coercion -> Coercion
    forall a b. (a -> b) -> a -> b
    $
            Type -> Coercion
    mkNomReflCo Type
    ty1

        go (CoercionTy Coercion
    co1) (CoercionTy Coercion
    co2)
          = Role -> Coercion -> Coercion -> Coercion -> Coercion
    mkProofIrrelCo Role
    Nominal Coercion
    kind_co Coercion
    co1 Coercion
    co2
          where
            kind_co :: Coercion
    kind_co = Type -> Type -> Coercion
    go (Coercion -> Type
    coercionType Coercion
    co1) (Coercion -> Type
    coercionType Coercion
    co2)

        go Type
    ty1 Type
    ty2
          = String -> SDoc -> Coercion
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "buildKindCoercion" ([SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    orig_ty1, Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    orig_ty2
                                               , Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty1, Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    ty2 ])

    {-
    %************************************************************************
    %*                                                                      *
           Coercion holes
    %*                                                                      *
    %************************************************************************
    -}

    has_co_hole_ty :: Type -> Monoid.Any
    has_co_hole_co :: Coercion -> Monoid.Any
    (Type -> Any
    has_co_hole_ty, [Type] -> Any
    _, Coercion -> Any
    has_co_hole_co, [Coercion] -> Any
    _)
      = TyCoFolder () Any
    -> ()
    -> (Type -> Any, [Type] -> Any, Coercion -> Any, [Coercion] -> Any)
    forall a env.
    Monoid a =>
    TyCoFolder env a
    -> env -> (Type -> a, [Type] -> a, Coercion -> a, [Coercion] -> a)
    foldTyCo TyCoFolder () Any
    forall {env}. TyCoFolder env Any
    folder ()
      where
        folder :: TyCoFolder env Any
    folder = TyCoFolder { tcf_view :: Type -> Maybe Type
    tcf_view  = Type -> Maybe Type
    noView
                            , tcf_tyvar :: env -> CoVar -> Any
    tcf_tyvar = Any -> env -> CoVar -> Any
    forall a b c. a -> b -> c -> a
    const2 (Bool -> Any
    Monoid.Any Bool
    False)
                            , tcf_covar :: env -> CoVar -> Any
    tcf_covar = Any -> env -> CoVar -> Any
    forall a b c. a -> b -> c -> a
    const2 (Bool -> Any
    Monoid.Any Bool
    False)
                            , tcf_hole :: env -> CoercionHole -> Any
    tcf_hole  = Any -> env -> CoercionHole -> Any
    forall a b c. a -> b -> c -> a
    const2 (Bool -> Any
    Monoid.Any Bool
    True)
                            , tcf_tycobinder :: env -> CoVar -> ForAllTyFlag -> env
    tcf_tycobinder = env -> CoVar -> ForAllTyFlag -> env
    forall a b c. a -> b -> c -> a
    const2
                            }

    -- | Is there a coercion hole in this type?
    hasCoercionHoleTy :: Type -> Bool
    hasCoercionHoleTy :: Type -> Bool
    hasCoercionHoleTy = Any -> Bool
    Monoid.getAny (Any -> Bool) -> (Type -> Any) -> Type -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Type -> Any
    has_co_hole_ty

    -- | Is there a coercion hole in this coercion?
    hasCoercionHoleCo :: Coercion -> Bool
    hasCoercionHoleCo :: Coercion -> Bool
    hasCoercionHoleCo = Any -> Bool
    Monoid.getAny (Any -> Bool) -> (Coercion -> Any) -> Coercion -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Coercion -> Any
    has_co_hole_co

    hasThisCoercionHoleTy :: Type -> CoercionHole -> Bool
    hasThisCoercionHoleTy :: Type -> CoercionHole -> Bool
    hasThisCoercionHoleTy Type
    ty CoercionHole
    hole = Any -> Bool
    Monoid.getAny (Type -> Any
    f Type
    ty)
      where
        (Type -> Any
    f, [Type] -> Any
    _, Coercion -> Any
    _, [Coercion] -> Any
    _) = TyCoFolder () Any
    -> ()
    -> (Type -> Any, [Type] -> Any, Coercion -> Any, [Coercion] -> Any)
    forall a env.
    Monoid a =>
    TyCoFolder env a
    -> env -> (Type -> a, [Type] -> a, Coercion -> a, [Coercion] -> a)
    foldTyCo TyCoFolder () Any
    folder ()

        folder :: TyCoFolder () Any
    folder = TyCoFolder { tcf_view :: Type -> Maybe Type
    tcf_view  = Type -> Maybe Type
    noView
                            , tcf_tyvar :: () -> CoVar -> Any
    tcf_tyvar = Any -> () -> CoVar -> Any
    forall a b c. a -> b -> c -> a
    const2 (Bool -> Any
    Monoid.Any Bool
    False)
                            , tcf_covar :: () -> CoVar -> Any
    tcf_covar = Any -> () -> CoVar -> Any
    forall a b c. a -> b -> c -> a
    const2 (Bool -> Any
    Monoid.Any Bool
    False)
                            , tcf_hole :: () -> CoercionHole -> Any
    tcf_hole  = \ ()
    _ CoercionHole
    h -> Bool -> Any
    Monoid.Any (CoercionHole -> Unique
    forall a. Uniquable a => a -> Unique
    getUnique CoercionHole
    h Unique -> Unique -> Bool
    forall a. Eq a => a -> a -> Bool
    == CoercionHole -> Unique
    forall a. Uniquable a => a -> Unique
    getUnique CoercionHole
    hole)
                            , tcf_tycobinder :: () -> CoVar -> ForAllTyFlag -> ()
    tcf_tycobinder = () -> CoVar -> ForAllTyFlag -> ()
    forall a b c. a -> b -> c -> a
    const2
                            }

    -- | Set the type of a 'CoercionHole'
    setCoHoleType :: CoercionHole -> Type -> CoercionHole
    setCoHoleType :: CoercionHole -> Type -> CoercionHole
    setCoHoleType CoercionHole
    h Type
    t = CoercionHole -> CoVar -> CoercionHole
    setCoHoleCoVar CoercionHole
    h (CoVar -> Type -> CoVar
    setVarType (CoercionHole -> CoVar
    coHoleCoVar CoercionHole
    h) Type
    t)