    -- | This module implements some analyses of Core expressions necessary for
    -- "Test.Inspection". Normally, users of this package can ignore this module.
    {-# LANGUAGE CPP, FlexibleContexts, PatternSynonyms, MultiWayIf, ViewPatterns #-}
    module Test.Inspection.Core
      ( slice
      , pprSlice
      , pprSliceDifference
      , eqSlice
      , eqSlice'
      , freeOfType
      , freeOfTerm
      , doesNotAllocate
      , doesNotContainTypeClasses
      ) where

    #if MIN_VERSION_ghc(9,0,0)
    import GHC.Builtin.Types (isCTupleTyConName)
    import GHC.Core
    import GHC.Core.Utils
    import GHC.Core.TyCo.Rep
    import GHC.Core.Type
    import GHC.Types.Var as Var
    import GHC.Types.Var.Set (mkVarSet)
    import GHC.Types.Id
    import GHC.Types.Name
    import GHC.Types.Literal
    import GHC.Types.Var.Env
    import GHC.Types.Unique
    import GHC.Utils.Outputable as Outputable
    import GHC.Core.Ppr
    import GHC.Core.Subst
    import GHC.Core.Coercion
    import GHC.Utils.Misc
    import GHC.Core.DataCon
    import GHC.Core.TyCon (TyCon, isClassTyCon)
    #else
    import TysWiredIn (isCTupleTyConName)
    import CoreSyn
    import CoreUtils
    import CoreSubst
    import TyCoRep
    import Type
    import Var
    import VarSet (mkVarSet)
    import Id
    import Literal
    import Name
    import VarEnv
    import Outputable
    import PprCore
    import Coercion
    import Util
    import DataCon
    import Unique
    import TyCon (TyCon, isClassTyCon)
    #endif

    #if MIN_VERSION_ghc(9,2,0)
    import GHC.Types.Tickish
    #endif

    #if MIN_VERSION_ghc(9,6,0)
    import GHC.Core.TyCo.Compare (eqTypeX)
    #endif

    import qualified Data.Set as S
    import Control.Monad (unless)
    import Control.Monad.State.Strict (execState,  modify', gets)
    import Data.List (nub, intercalate)
    import Data.Maybe (listToMaybe, fromJust)
    import Data.Either (isRight)

    import Test.Inspection (Equivalence (..))

    -- Uncomment to enable debug traces
    -- #define DEBUG_TRACE

    #ifdef DEBUG_TRACE
    import Debug.Trace

    tracePut :: Monad m => Int -> String -> String -> m ()
    tracePut lv name msg = traceM $ replicate lv ' ' ++ name ++ ": " ++ msg
    #else
    tracePut :: Monad m => Int -> String -> String -> m ()
    tracePut :: forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    _  String
    _    String
    _ = () -> m ()
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    #endif

    #if !MIN_VERSION_ghc(9,2,0)
    pattern Alt :: a -> b -> c -> (a, b, c)
    pattern Alt a b c = (a, b, c)
    {-# COMPLETE Alt #-}
    #endif

    type Slice = [(Var, CoreExpr)]

    -- | Selects those bindings that define the given variable (with this variable first)
    slice :: [(Var, CoreExpr)] -> Var -> Slice
    slice :: [(Var, CoreExpr)] -> Var -> [(Var, CoreExpr)]
    slice [(Var, CoreExpr)]
    binds Var
    v
        | Just CoreExpr
    e <- Var -> [(Var, CoreExpr)] -> Maybe CoreExpr
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Var
    v [(Var, CoreExpr)]
    binds
        = (Var
    v,CoreExpr
    e) (Var, CoreExpr) -> [(Var, CoreExpr)] -> [(Var, CoreExpr)]
    forall a. a -> [a] -> [a]
    : [(Var
    v',CoreExpr
    e) | (Var
    v',CoreExpr
    e) <- [(Var, CoreExpr)]
    binds, Var
    v' Var -> Var -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Var
    v, Var
    v' Var -> Set Var -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.member` Set Var
    used ]
        | Bool
    otherwise
        = String -> [(Var, CoreExpr)]
    forall a. HasCallStack => String -> a
    error String
    "slice: cannot find given variable in bindings"
      where
        used :: Set Var
    used = State (Set Var) () -> Set Var -> Set Var
    forall s a. State s a -> s -> s
    execState (Var -> State (Set Var) ()
    forall {m :: * -> *}. MonadState (Set Var) m => Var -> m ()
    goV Var
    v) Set Var
    forall a. Set a
    S.empty

        local :: Set Var
    local = [Var] -> Set Var
    forall a. Ord a => [a] -> Set a
    S.fromList (((Var, CoreExpr) -> Var) -> [(Var, CoreExpr)] -> [Var]
    forall a b. (a -> b) -> [a] -> [b]
    map (Var, CoreExpr) -> Var
    forall a b. (a, b) -> a
    fst [(Var, CoreExpr)]
    binds)
        goV :: Var -> m ()
    goV Var
    v | Var
    v Var -> Set Var -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.member` Set Var
    local = do
            seen <- (Set Var -> Bool) -> m Bool
    forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
    gets (Var
    v Var -> Set Var -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.member`)
            unless seen $ do
                modify' (S.insert v)
                let e = Maybe CoreExpr -> CoreExpr
    forall a. HasCallStack => Maybe a -> a
    fromJust (Maybe CoreExpr -> CoreExpr) -> Maybe CoreExpr -> CoreExpr
    forall a b. (a -> b) -> a -> b
    $ Var -> [(Var, CoreExpr)] -> Maybe CoreExpr
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Var
    v [(Var, CoreExpr)]
    binds
                go e
              | Bool
    otherwise = () -> m ()
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

        go :: CoreExpr -> m ()
    go (Var Var
    v)                     = Var -> m ()
    goV Var
    v
        go (Lit Literal
    _ )                    = () -> m ()
    forall a. a -> m a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()
        go (App CoreExpr
    e CoreExpr
    arg) | CoreExpr -> Bool
    forall b. Expr b -> Bool
    isTyCoArg CoreExpr
    arg = CoreExpr -> m ()
    go CoreExpr
    e
        go (App CoreExpr
    e CoreExpr
    arg)                 = CoreExpr -> m ()
    go CoreExpr
    e m () -> m () -> m ()
    forall a b. m a -> m b -> m b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> CoreExpr -> m ()
    go CoreExpr
    arg
        go (Lam Var
    _ CoreExpr
    e)                   = CoreExpr -> m ()
    go CoreExpr
    e
        go (Let Bind Var
    bind CoreExpr
    body)             = (CoreExpr -> m ()) -> [CoreExpr] -> m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ CoreExpr -> m ()
    go (Bind Var -> [CoreExpr]
    forall b. Bind b -> [Expr b]
    rhssOfBind Bind Var
    bind) m () -> m () -> m ()
    forall a b. m a -> m b -> m b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> CoreExpr -> m ()
    go CoreExpr
    body
        go (Case CoreExpr
    s Var
    _ Type
    _ [Alt Var]
    alts)           = CoreExpr -> m ()
    go CoreExpr
    s m () -> m () -> m ()
    forall a b. m a -> m b -> m b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> (Alt Var -> m ()) -> [Alt Var] -> m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Alt Var -> m ()
    goA [Alt Var]
    alts
        go (Cast CoreExpr
    e CoercionR
    _)                  = CoreExpr -> m ()
    go CoreExpr
    e
        go (Tick CoreTickish
    _ CoreExpr
    e)                  = CoreExpr -> m ()
    go CoreExpr
    e
        go (Type Type
    _)                    = () -> m ()
    forall a. a -> m a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()
        go (Coercion CoercionR
    _)                = () -> m ()
    forall a. a -> m a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()

        goA :: Alt Var -> m ()
    goA (Alt AltCon
    _ [Var]
    _ CoreExpr
    e) = CoreExpr -> m ()
    go CoreExpr
    e

    -- | Pretty-print a slice
    pprSlice :: Slice -> SDoc
    pprSlice :: [(Var, CoreExpr)] -> SDoc
    pprSlice [(Var, CoreExpr)]
    slice =
        SDoc -> SDoc
    withLessDetail (SDoc -> SDoc) -> SDoc -> SDoc
    forall a b. (a -> b) -> a -> b
    $ [Bind Var] -> SDoc
    forall b. OutputableBndr b => [Bind b] -> SDoc
    pprCoreBindings [ Var -> CoreExpr -> Bind Var
    forall b. b -> Expr b -> Bind b
    NonRec Var
    v CoreExpr
    e  | (Var
    v,CoreExpr
    e) <- [(Var, CoreExpr)]
    slice ]

    -- | Pretty-print two slices, after removing variables occurring in both
    pprSliceDifference :: Slice -> Slice -> SDoc
    pprSliceDifference :: [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> SDoc
    pprSliceDifference [(Var, CoreExpr)]
    slice1 [(Var, CoreExpr)]
    slice2
        | [(Var
    v1,CoreExpr
    e1)] <- [(Var, CoreExpr)]
    slice1'
        , [(Var
    v2,CoreExpr
    e2)] <- [(Var, CoreExpr)]
    slice2'
        = InScopeSet -> Var -> Var -> CoreExpr -> CoreExpr -> SDoc
    pprSingletonSliceDifference (VarSet -> InScopeSet
    mkInScopeSet ([Var] -> VarSet
    mkVarSet (Set Var -> [Var]
    forall a. Set a -> [a]
    S.toList Set Var
    both))) Var
    v1 Var
    v2 CoreExpr
    e1 CoreExpr
    e2

        | Bool
    otherwise =
            SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "LHS" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    Outputable.<> SDoc
    forall doc. IsLine doc => doc
    colon) Int
    4 ([(Var, CoreExpr)] -> SDoc
    pprSlice [(Var, CoreExpr)]
    slice1') SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$
            SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "RHS" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    Outputable.<> SDoc
    forall doc. IsLine doc => doc
    colon) Int
    4 ([(Var, CoreExpr)] -> SDoc
    pprSlice [(Var, CoreExpr)]
    slice2')
      where
        both :: Set Var
    both = Set Var -> Set Var -> Set Var
    forall a. Ord a => Set a -> Set a -> Set a
    S.intersection ([Var] -> Set Var
    forall a. Ord a => [a] -> Set a
    S.fromList (((Var, CoreExpr) -> Var) -> [(Var, CoreExpr)] -> [Var]
    forall a b. (a -> b) -> [a] -> [b]
    map (Var, CoreExpr) -> Var
    forall a b. (a, b) -> a
    fst [(Var, CoreExpr)]
    slice1)) ([Var] -> Set Var
    forall a. Ord a => [a] -> Set a
    S.fromList (((Var, CoreExpr) -> Var) -> [(Var, CoreExpr)] -> [Var]
    forall a b. (a -> b) -> [a] -> [b]
    map (Var, CoreExpr) -> Var
    forall a b. (a, b) -> a
    fst [(Var, CoreExpr)]
    slice2))
        slice1' :: [(Var, CoreExpr)]
    slice1' = ((Var, CoreExpr) -> Bool) -> [(Var, CoreExpr)] -> [(Var, CoreExpr)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (\(Var
    v,CoreExpr
    _) -> Var
    v Var -> Set Var -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.notMember` Set Var
    both) [(Var, CoreExpr)]
    slice1
        slice2' :: [(Var, CoreExpr)]
    slice2' = ((Var, CoreExpr) -> Bool) -> [(Var, CoreExpr)] -> [(Var, CoreExpr)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (\(Var
    v,CoreExpr
    _) -> Var
    v Var -> Set Var -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.notMember` Set Var
    both) [(Var, CoreExpr)]
    slice2

    pprSingletonSliceDifference :: InScopeSet -> Var -> Var -> CoreExpr -> CoreExpr -> SDoc
    pprSingletonSliceDifference :: InScopeSet -> Var -> Var -> CoreExpr -> CoreExpr -> SDoc
    pprSingletonSliceDifference InScopeSet
    iss Var
    v1 Var
    v2 CoreExpr
    e1 CoreExpr
    e2 =
        SDoc -> SDoc
    ctxDoc (SDoc -> SDoc) -> SDoc -> SDoc
    forall a b. (a -> b) -> a -> b
    $
        SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "LHS" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    Outputable.<> SDoc
    forall doc. IsLine doc => doc
    colon) Int
    4 (SDoc -> Int -> SDoc -> SDoc
    hang (Var -> SDoc
    forall a. OutputableBndr a => a -> SDoc
    pprPrefixOcc Var
    v1) Int
    2 (SDoc
    eqSign SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> CoreExpr -> SDoc
    forall b. OutputableBndr b => Expr b -> SDoc
    pprCoreExpr CoreExpr
    e1')) SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$
        SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "RHS" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    Outputable.<> SDoc
    forall doc. IsLine doc => doc
    colon) Int
    4 (SDoc -> Int -> SDoc -> SDoc
    hang (Var -> SDoc
    forall a. OutputableBndr a => a -> SDoc
    pprPrefixOcc Var
    v2) Int
    2 (SDoc
    eqSign SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> CoreExpr -> SDoc
    forall b. OutputableBndr b => Expr b -> SDoc
    pprCoreExpr CoreExpr
    e2'))
      where
        hasContext :: Bool
    hasContext = Bool -> Bool
    not ([(Var, Var)] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [(Var, Var)]
    ctxt)

        ctxDoc :: SDoc -> SDoc
    ctxDoc | Bool
    hasContext = SDoc -> SDoc
    forall a. a -> a
    id
               | Bool
    otherwise = (SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "In") Int
    4 (CoreExpr -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (CoreExpr -> SDoc) -> CoreExpr -> SDoc
    forall a b. (a -> b) -> a -> b
    $ [Var] -> CoreExpr
    mkContextExpr ([Var] -> [Var]
    forall a. [a] -> [a]
    reverse (((Var, Var) -> Var) -> [(Var, Var)] -> [Var]
    forall a b. (a -> b) -> [a] -> [b]
    map (Var, Var) -> Var
    forall a b. (a, b) -> b
    snd [(Var, Var)]
    ctxt))) SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$)

        eqSign :: SDoc
    eqSign | Bool
    hasContext = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "= ..."
               | Bool
    otherwise  = SDoc
    forall doc. IsLine doc => doc
    equals

        (CoreExpr
    e1', CoreExpr
    e2', [(Var, Var)]
    ctxt) = CoreExpr
    -> CoreExpr
    -> [(Var, Var)]
    -> RnEnv2
    -> (CoreExpr, CoreExpr, [(Var, Var)])
    go CoreExpr
    e1 CoreExpr
    e2 [] (InScopeSet -> RnEnv2
    mkRnEnv2 InScopeSet
    emptyInScopeSet)

        go :: CoreExpr -> CoreExpr -> [(Var, Var)] -> RnEnv2 -> (CoreExpr, CoreExpr, [(Var, Var)])
        go :: CoreExpr
    -> CoreExpr
    -> [(Var, Var)]
    -> RnEnv2
    -> (CoreExpr, CoreExpr, [(Var, Var)])
    go (Lam Var
    b1 CoreExpr
    t1) (Lam Var
    b2 CoreExpr
    t2) [(Var, Var)]
    ctxt RnEnv2
    env
            | RnEnv2 -> Type -> Type -> Bool
    eqTypeX RnEnv2
    env (Var -> Type
    varType Var
    b1) (Var -> Type
    varType Var
    b2)
            = CoreExpr
    -> CoreExpr
    -> [(Var, Var)]
    -> RnEnv2
    -> (CoreExpr, CoreExpr, [(Var, Var)])
    go CoreExpr
    t1 CoreExpr
    t2 ((Var
    b1,Var
    b2)(Var, Var) -> [(Var, Var)] -> [(Var, Var)]
    forall a. a -> [a] -> [a]
    :[(Var, Var)]
    ctxt) (RnEnv2 -> Var -> Var -> RnEnv2
    rnBndr2 RnEnv2
    env Var
    b1 Var
    b2)
          where
        go CoreExpr
    x CoreExpr
    y [(Var, Var)]
    ctxt RnEnv2
    _env = (InScopeSet -> [(Var, Var)] -> CoreExpr -> CoreExpr
    rename InScopeSet
    iss [(Var, Var)]
    ctxt CoreExpr
    x, CoreExpr
    y, [(Var, Var)]
    ctxt)

        mkContextExpr :: [Var] -> CoreExpr
        mkContextExpr :: [Var] -> CoreExpr
    mkContextExpr []       = CoreExpr
    ellipsis
        mkContextExpr (Var
    x:[Var]
    rest) = Var -> CoreExpr -> CoreExpr
    forall b. b -> Expr b -> Expr b
    Lam Var
    x ([Var] -> CoreExpr
    mkContextExpr [Var]
    rest)

        ellipsis :: CoreExpr
    #if MIN_VERSION_ghc(8,8,0)
        ellipsis :: CoreExpr
    ellipsis = Literal -> CoreExpr
    forall b. Literal -> Expr b
    Lit (Literal -> CoreExpr) -> Literal -> CoreExpr
    forall a b. (a -> b) -> a -> b
    $ String -> Literal
    mkLitString String
    "..."
    #else
        ellipsis = Lit $ mkMachString "..."
    #endif

    withLessDetail :: SDoc -> SDoc
    #if MIN_VERSION_GLASGOW_HASKELL(8,2,0,0) && !MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
    withLessDetail sdoc = sdocWithDynFlags $ \dflags ->
         withPprStyle (defaultUserStyle dflags) sdoc
    #else
    withLessDetail :: SDoc -> SDoc
    withLessDetail SDoc
    sdoc = PprStyle -> SDoc -> SDoc
    withPprStyle PprStyle
    defaultUserStyle SDoc
    sdoc
    #endif

    -- | Equality name environment.
    -- This environment contains top-level and let-bound definitions
    -- (no lambda arguments).
    data EqEnv = EqEnv !Int [(Var, (Int, CoreExpr))]  [(Var, (Int, CoreExpr))]

    -- | Lookup left and right variables in EqEnv.
    lookupEqEnv :: Var -> Var -> EqEnv -> Maybe (Int, Int, CoreExpr, CoreExpr)
    lookupEqEnv :: Var -> Var -> EqEnv -> Maybe (Int, Int, CoreExpr, CoreExpr)
    lookupEqEnv Var
    x Var
    y (EqEnv Int
    _ [(Var, (Int, CoreExpr))]
    env1 [(Var, (Int, CoreExpr))]
    env2)
        | Just (Int
    i, CoreExpr
    e1) <- Var -> [(Var, (Int, CoreExpr))] -> Maybe (Int, CoreExpr)
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Var
    x [(Var, (Int, CoreExpr))]
    env1
        , Just (Int
    j, CoreExpr
    e2) <- Var -> [(Var, (Int, CoreExpr))] -> Maybe (Int, CoreExpr)
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Var
    y [(Var, (Int, CoreExpr))]
    env2
        = (Int, Int, CoreExpr, CoreExpr)
    -> Maybe (Int, Int, CoreExpr, CoreExpr)
    forall a. a -> Maybe a
    Just (Int
    i, Int
    j, CoreExpr
    e1, CoreExpr
    e2)

        | Bool
    otherwise
        = Maybe (Int, Int, CoreExpr, CoreExpr)
    forall a. Maybe a
    Nothing

    initialEqEnv :: [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> EqEnv
    initialEqEnv :: [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> EqEnv
    initialEqEnv [(Var, CoreExpr)]
    ls [(Var, CoreExpr)]
    rs = Int
    -> [(Var, (Int, CoreExpr))] -> [(Var, (Int, CoreExpr))] -> EqEnv
    EqEnv Int
    1
        [ (Var
    x, (Int
    0, CoreExpr
    e1)) | (Var
    x, CoreExpr
    e1) <- [(Var, CoreExpr)]
    ls ]
        [ (Var
    y, (Int
    0, CoreExpr
    e2)) | (Var
    y, CoreExpr
    e2) <- [(Var, CoreExpr)]
    rs ]

    bindEqEnv :: [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> EqEnv -> EqEnv
    bindEqEnv :: [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> EqEnv -> EqEnv
    bindEqEnv [(Var, CoreExpr)]
    ls [(Var, CoreExpr)]
    rs (EqEnv Int
    i [(Var, (Int, CoreExpr))]
    env1 [(Var, (Int, CoreExpr))]
    env2)= Int
    -> [(Var, (Int, CoreExpr))] -> [(Var, (Int, CoreExpr))] -> EqEnv
    EqEnv (Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1)
        ([ (Var
    x, (Int
    i, CoreExpr
    e1)) | (Var
    x, CoreExpr
    e1) <- [(Var, CoreExpr)]
    ls ] [(Var, (Int, CoreExpr))]
    -> [(Var, (Int, CoreExpr))] -> [(Var, (Int, CoreExpr))]
    forall a. [a] -> [a] -> [a]
    ++ [(Var, (Int, CoreExpr))]
    env1)
        ([ (Var
    y, (Int
    i, CoreExpr
    e2)) | (Var
    y, CoreExpr
    e2) <- [(Var, CoreExpr)]
    rs ] [(Var, (Int, CoreExpr))]
    -> [(Var, (Int, CoreExpr))] -> [(Var, (Int, CoreExpr))]
    forall a. [a] -> [a] -> [a]
    ++ [(Var, (Int, CoreExpr))]
    env2)

    -- | This is a heuristic, which only works if both slices
    -- have auxiliary variables in the right order.
    -- (This is mostly to work-around the buggy CSE in GHC-8.0)
    -- It also breaks if there is shadowing.
    eqSlice :: Equivalence -> Slice -> Slice -> Bool
    eqSlice :: Equivalence -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> Bool
    eqSlice Equivalence
    eqv [(Var, CoreExpr)]
    l [(Var, CoreExpr)]
    r = Either SDoc () -> Bool
    forall a b. Either a b -> Bool
    isRight (Equivalence
    -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> Either SDoc ()
    eqSlice' Equivalence
    eqv [(Var, CoreExpr)]
    l [(Var, CoreExpr)]
    r)

    -- | Like 'eqSlice' but also returns an explanation of inequality.
    eqSlice' :: Equivalence -> Slice -> Slice -> Either SDoc ()
    eqSlice' :: Equivalence
    -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> Either SDoc ()
    eqSlice' Equivalence
    _ [] [] = () -> Either SDoc ()
    forall a b. b -> Either a b
    Right ()
    eqSlice' Equivalence
    _ ((Var
    v,CoreExpr
    _) : [(Var, CoreExpr)]
    _) [] = SDoc -> Either SDoc ()
    forall a b. a -> Either a b
    Left (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v
    eqSlice' Equivalence
    _ [] ((Var
    v,CoreExpr
    _) : [(Var, CoreExpr)]
    _) = SDoc -> Either SDoc ()
    forall a b. a -> Either a b
    Left (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v
      -- Mostly defensive programming (slices should not be empty)
    eqSlice' Equivalence
    eqv slice1 :: [(Var, CoreExpr)]
    slice1@((Var
    head1, CoreExpr
    def1) : [(Var, CoreExpr)]
    _) slice2 :: [(Var, CoreExpr)]
    slice2@((Var
    head2, CoreExpr
    def2) : [(Var, CoreExpr)]
    _) = do
        Var -> CoreExpr -> Var -> CoreExpr -> Either SDoc ()
    goStart Var
    head1 CoreExpr
    def1 Var
    head2 CoreExpr
    def2
      where
        -- ignore types and hpc ticks
        it :: Bool
        it :: Bool
    it = case Equivalence
    eqv of
            Equivalence
    StrictEquiv              -> Bool
    False
            Equivalence
    IgnoreTypesAndTicksEquiv -> Bool
    True
            Equivalence
    UnorderedLetsEquiv       -> Bool
    True

        -- unordered lets
        ul :: Bool
        ul :: Bool
    ul = case Equivalence
    eqv of
            Equivalence
    StrictEquiv              -> Bool
    False
            Equivalence
    IgnoreTypesAndTicksEquiv -> Bool
    False
            Equivalence
    UnorderedLetsEquiv       -> Bool
    True

        goStart :: Var -> CoreExpr -> Var -> CoreExpr -> Either SDoc ()
        goStart :: Var -> CoreExpr -> Var -> CoreExpr -> Either SDoc ()
    goStart Var
    x CoreExpr
    e1 Var
    y CoreExpr
    e2 = do
            Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    0 String
    "TOP" (Var -> String
    varToString Var
    x String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =?= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    y)
            if | Just Var
    x'  <- CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e1
               , Just CoreExpr
    e1' <- Var -> [(Var, CoreExpr)] -> Maybe CoreExpr
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Var
    x' [(Var, CoreExpr)]
    slice1
               -> Var -> CoreExpr -> Var -> CoreExpr -> Either SDoc ()
    goStart Var
    x' CoreExpr
    e1' Var
    y CoreExpr
    e2

               | Just Var
    y'  <- CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e2
               , Just CoreExpr
    e2' <- Var -> [(Var, CoreExpr)] -> Maybe CoreExpr
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Var
    y' [(Var, CoreExpr)]
    slice2
               -> Var -> CoreExpr -> Var -> CoreExpr -> Either SDoc ()
    goStart Var
    x CoreExpr
    e1 Var
    y' CoreExpr
    e2'

                -- otherwise if neither x and y expressions are variables
                -- 1. compare the expressions (already assuming that x and y are equal)
                -- 2. comparison may create new obligations, loop.
               | Bool
    otherwise
               -> do
                  let env :: RnEnv2
    env = RnEnv2 -> Var -> Var -> RnEnv2
    rnBndr2 (InScopeSet -> RnEnv2
    mkRnEnv2 InScopeSet
    emptyInScopeSet) Var
    x Var
    y
                      ee :: EqEnv
    ee  = [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> EqEnv
    initialEqEnv [(Var, CoreExpr)]
    slice1 [(Var, CoreExpr)]
    slice2
                  [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [] Int
    0 RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2

        essentiallyVar :: CoreExpr -> Maybe Var
        essentiallyVar :: CoreExpr -> Maybe Var
    essentiallyVar (App CoreExpr
    e CoreExpr
    a)  | Bool
    it, CoreExpr -> Bool
    forall b. Expr b -> Bool
    isTyCoArg CoreExpr
    a = CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e
        essentiallyVar (Lam Var
    v CoreExpr
    e)  | Bool
    it, Var -> Bool
    isTyCoVar Var
    v = CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e
        essentiallyVar (Cast CoreExpr
    e CoercionR
    _) | Bool
    it              = CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e
    #if MIN_VERSION_ghc(9,0,0)
        essentiallyVar (Case CoreExpr
    s Var
    b Type
    _ [Alt Var]
    alts) | Bool
    it, Just CoreExpr
    e <- CoreExpr -> Var -> [Alt Var] -> Maybe CoreExpr
    isUnsafeEqualityCase CoreExpr
    s Var
    b [Alt Var]
    alts = CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e
    #endif
        essentiallyVar (Var Var
    v)                      = Var -> Maybe Var
    forall a. a -> Maybe a
    Just Var
    v
        essentiallyVar (Tick HpcTick{} CoreExpr
    e) | Bool
    it      = CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e
        essentiallyVar (Tick SourceNote{} CoreExpr
    e)        = CoreExpr -> Maybe Var
    essentiallyVar CoreExpr
    e
        essentiallyVar CoreExpr
    _                            = Maybe Var
    forall a. Maybe a
    Nothing

        -- report inequality
        inequality :: [SDoc] -> SDoc -> Either SDoc a
        inequality :: forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality []  SDoc
    err = SDoc -> Either SDoc a
    forall a b. a -> Either a b
    Left SDoc
    err
        inequality [SDoc]
    ctx SDoc
    err = SDoc -> Either SDoc a
    forall a b. a -> Either a b
    Left (SDoc -> Either SDoc a) -> SDoc -> Either SDoc a
    forall a b. (a -> b) -> a -> b
    $ SDoc
    err SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "in") Int
    2 ([SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [SDoc]
    ctx)

        go :: [SDoc] -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
        go :: [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (CoreExpr -> Maybe Var
    essentiallyVar -> Just Var
    v1) (CoreExpr -> Maybe Var
    essentiallyVar -> Just Var
    v2) = do
            -- NOTE: The ordering of this checks is important.
            --
            -- See example https://github.com/nomeata/inspection-testing/pull/89#issuecomment-2967774956
            -- GHC may use same name for local names in different bindings.
            --
            -- Therefore we first check for already visited and lambda-bound variables.
            -- (inRnEnvL/inRnEnvR checks are important so we don't confuse for unbound variables).
            -- We need to this first to break loops of recursive definitions,.
            --
            -- Then we test whether variables are top or local-let bound.
            -- If so, we proceed to compare their definitions.
            --
            -- Lastly we check whether variables are equal.
            -- This case checks for any global names.
            if
               | RnEnv2 -> Var -> Bool
    inRnEnvL RnEnv2
    env Var
    v1
               , RnEnv2 -> Var -> Bool
    inRnEnvR RnEnv2
    env Var
    v2
               , RnEnv2 -> Var -> Var
    rnOccL RnEnv2
    env Var
    v1 Var -> Var -> Bool
    forall a. Eq a => a -> a -> Bool
    == RnEnv2 -> Var -> Var
    rnOccR RnEnv2
    env Var
    v2 -> do
                Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "VAR" (Var -> String
    varToString Var
    v1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =?= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    v2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " IN ENV")
                () -> Either SDoc ()
    forall a. a -> Either SDoc a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

               | Just (Int
    i, Int
    j, CoreExpr
    e1, CoreExpr
    e2) <- Var -> Var -> EqEnv -> Maybe (Int, Int, CoreExpr, CoreExpr)
    lookupEqEnv Var
    v1 Var
    v2 EqEnv
    ee ->
                 -- we check that levels are the same
                 -- if they are not we fail immediately and not fall-back further.
                 if Int
    i Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    j
                 then do
                   Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "VAR" (Var -> String
    varToString Var
    v1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =?= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    v2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " BOUND " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall a. Show a => a -> String
    show Int
    i)
                   let ctx' :: [SDoc]
    ctx' = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "comparing definitions of" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v1 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
    <+> Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v2 SDoc -> [SDoc] -> [SDoc]
    forall a. a -> [a] -> [a]
    : [SDoc]
    ctx
                   let env' :: RnEnv2
    env' = RnEnv2 -> Var -> Var -> RnEnv2
    rnBndr2 RnEnv2
    env Var
    v1 Var
    v2
                   [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx' Int
    lv RnEnv2
    env' EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
                 else do
                   Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "VAR" (Var -> String
    varToString Var
    v1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =?= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    v2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " BOUND IN DIFFERENT LETS " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall a. Show a => a -> String
    show Int
    i String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " /= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall a. Show a => a -> String
    show Int
    j)
                   [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    hsep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "variables", Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v2, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "are bound in different lets" ]

               | Var
    v1 Var -> Var -> Bool
    forall a. Eq a => a -> a -> Bool
    == Var
    v2 -> do
                Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "VAR" (Var -> String
    varToString Var
    v1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =?= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    v2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " SAME")
                () -> Either SDoc ()
    forall a. a -> Either SDoc a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

               | Bool
    otherwise -> do
                Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "VAR" (Var -> String
    varToString Var
    v1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =?= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    v2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " NOT EQUAL")
                [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    hsep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal variables", Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Var
    v2 ]

        go [SDoc]
    ctx Int
    lv RnEnv2
    _   EqEnv
    _  (Lit Literal
    lit1)    (Lit Literal
    lit2)        = do
            Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "LIT" String
    "???" -- no Show for Literal :(
            Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless (Literal
    lit1 Literal -> Literal -> Bool
    forall a. Eq a => a -> a -> Bool
    == Literal
    lit2) (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal literals", Literal -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Literal
    lit1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", Literal -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Literal
    lit2 ]

        go [SDoc]
    ctx Int
    _  RnEnv2
    env EqEnv
    _  (Type Type
    t1)     (Type Type
    t2)         =
            [SDoc] -> RnEnv2 -> Type -> Type -> Either SDoc ()
    goTypes [SDoc]
    ctx RnEnv2
    env Type
    t1 Type
    t2

        go [SDoc]
    ctx Int
    _  RnEnv2
    env EqEnv
    _  (Coercion CoercionR
    co1) (Coercion CoercionR
    co2)   =
            [SDoc] -> RnEnv2 -> CoercionR -> CoercionR -> Either SDoc ()
    goCoercions [SDoc]
    ctx RnEnv2
    env CoercionR
    co1 CoercionR
    co2

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Cast CoreExpr
    e1 CoercionR
    _) CoreExpr
    e2 | Bool
    it             = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 (Cast CoreExpr
    e2 CoercionR
    _) | Bool
    it             = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
    #if MIN_VERSION_ghc(9,0,0)
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Case CoreExpr
    s Var
    b Type
    _ [Alt Var]
    alts) CoreExpr
    e2 | Bool
    it, Just CoreExpr
    e1 <- CoreExpr -> Var -> [Alt Var] -> Maybe CoreExpr
    isUnsafeEqualityCase CoreExpr
    s Var
    b [Alt Var]
    alts = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 (Case CoreExpr
    s Var
    b Type
    _ [Alt Var]
    alts) | Bool
    it, Just CoreExpr
    e2 <- CoreExpr -> Var -> [Alt Var] -> Maybe CoreExpr
    isUnsafeEqualityCase CoreExpr
    s Var
    b [Alt Var]
    alts = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
    #endif
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Cast CoreExpr
    e1 CoercionR
    co1) (Cast CoreExpr
    e2 CoercionR
    co2)     = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "CAST" String
    "" ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
                                                       [SDoc] -> RnEnv2 -> CoercionR -> CoercionR -> Either SDoc ()
    goCoercions [SDoc]
    ctx RnEnv2
    env CoercionR
    co1 CoercionR
    co2
                                                       [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (App CoreExpr
    e1 CoreExpr
    a) CoreExpr
    e2 | Bool
    it, CoreExpr -> Bool
    forall b. Expr b -> Bool
    isTyCoArg CoreExpr
    a = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 (App CoreExpr
    e2 CoreExpr
    a) | Bool
    it, CoreExpr -> Bool
    forall b. Expr b -> Bool
    isTyCoArg CoreExpr
    a = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (App CoreExpr
    f1 CoreExpr
    a1)   (App CoreExpr
    f2 CoreExpr
    a2)       = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "APP" String
    "" ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
                                                       [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    f1 CoreExpr
    f2
                                                       [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    a1 CoreExpr
    a2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Tick HpcTick{} CoreExpr
    e1) CoreExpr
    e2 | Bool
    it     = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 (Tick HpcTick{} CoreExpr
    e2) | Bool
    it     = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Tick SourceNote{} CoreExpr
    e1) CoreExpr
    e2       = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 (Tick SourceNote{} CoreExpr
    e2)       = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Tick CoreTickish
    n1 CoreExpr
    e1)  (Tick CoreTickish
    n2 CoreExpr
    e2)      = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "TICK" String
    "" ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
                                                       Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless (RnEnv2 -> CoreTickish -> CoreTickish -> Bool
    go_tick RnEnv2
    env CoreTickish
    n1 CoreTickish
    n2) (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal ticks"
                                                       [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Lam Var
    b CoreExpr
    e1) CoreExpr
    e2 | Bool
    it, Var -> Bool
    isTyCoVar Var
    b = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 (Lam Var
    b CoreExpr
    e2) | Bool
    it, Var -> Bool
    isTyCoVar Var
    b = [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Lam Var
    b1 CoreExpr
    e1)  (Lam Var
    b2 CoreExpr
    e2)        = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "LAM" (Var -> String
    varToString Var
    b1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " ~ " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Var -> String
    varToString Var
    b2) ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
               Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless Bool
    it (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> RnEnv2 -> Type -> Type -> Either SDoc ()
    goTypes [SDoc]
    ctx RnEnv2
    env (Var -> Type
    varType Var
    b1) (Var -> Type
    varType Var
    b2)
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv (RnEnv2 -> Var -> Var -> RnEnv2
    rnBndr2 RnEnv2
    env Var
    b1 Var
    b2) EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee e1 :: CoreExpr
    e1@(Let Bind Var
    _ CoreExpr
    _) e2 :: CoreExpr
    e2@(Let Bind Var
    _ CoreExpr
    _)
          | Bool
    ul
          , ([(Var, CoreExpr)]
    ps1, CoreExpr
    e1') <- CoreExpr -> ([(Var, CoreExpr)], CoreExpr)
    forall {a}. Expr a -> ([(a, Expr a)], Expr a)
    peelLets CoreExpr
    e1
          , ([(Var, CoreExpr)]
    ps2, CoreExpr
    e2') <- CoreExpr -> ([(Var, CoreExpr)], CoreExpr)
    forall {a}. Expr a -> ([(a, Expr a)], Expr a)
    peelLets CoreExpr
    e2
          = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "LET" ([(Var, CoreExpr)] -> String
    forall a. [(Var, a)] -> String
    showVars [(Var, CoreExpr)]
    ps1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " ~ " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [(Var, CoreExpr)] -> String
    forall a. [(Var, a)] -> String
    showVars [(Var, CoreExpr)]
    ps2) ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
               let ctx' :: [SDoc]
    ctx' = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "let bindings:" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> [(Var, CoreExpr)] -> SDoc
    forall a. [(Var, a)] -> SDoc
    pprVars [(Var, CoreExpr)]
    ps1 SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> [(Var, CoreExpr)] -> SDoc
    forall a. [(Var, a)] -> SDoc
    pprVars [(Var, CoreExpr)]
    ps2 SDoc -> [SDoc] -> [SDoc]
    forall a. a -> [a] -> [a]
    : [SDoc]
    ctx
               Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless ([(Var, CoreExpr)] -> [(Var, CoreExpr)] -> Bool
    forall a b. [a] -> [b] -> Bool
    equalLength [(Var, CoreExpr)]
    ps1 [(Var, CoreExpr)]
    ps2) (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "different amount of bindings in let"
               let ee' :: EqEnv
    ee' = [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> EqEnv -> EqEnv
    bindEqEnv [(Var, CoreExpr)]
    ps1 [(Var, CoreExpr)]
    ps2 EqEnv
    ee
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx' Int
    lv RnEnv2
    env EqEnv
    ee' CoreExpr
    e1' CoreExpr
    e2'

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Let (NonRec Var
    v1 CoreExpr
    r1) CoreExpr
    e1) (Let (NonRec Var
    v2 CoreExpr
    r2) CoreExpr
    e2)
          = do [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    r1 CoreExpr
    r2  -- No need to check binder types, since RHSs match
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv (RnEnv2 -> Var -> Var -> RnEnv2
    rnBndr2 RnEnv2
    env Var
    v1 Var
    v2) EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Let (Rec [(Var, CoreExpr)]
    ps1) CoreExpr
    e1) (Let (Rec [(Var, CoreExpr)]
    ps2) CoreExpr
    e2)
          = do
               Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless ([(Var, CoreExpr)] -> [(Var, CoreExpr)] -> Bool
    forall a b. [a] -> [b] -> Bool
    equalLength [(Var, CoreExpr)]
    ps1 [(Var, CoreExpr)]
    ps2) (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "different amount of bindings in recursive let"
               [Either SDoc ()] -> Either SDoc ()
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, Monad m) =>
    t (m a) -> m ()
    sequence_ ([Either SDoc ()] -> Either SDoc ())
    -> [Either SDoc ()] -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ (CoreExpr -> CoreExpr -> Either SDoc ())
    -> [CoreExpr] -> [CoreExpr] -> [Either SDoc ()]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith ([SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env' EqEnv
    ee) [CoreExpr]
    rs1 [CoreExpr]
    rs2
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env' EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
          where
            bs1, bs2 :: [CoreBndr]
            rs1, rs2 :: [CoreExpr]

            ([Var]
    bs1,[CoreExpr]
    rs1) = [(Var, CoreExpr)] -> ([Var], [CoreExpr])
    forall a b. [(a, b)] -> ([a], [b])
    unzip [(Var, CoreExpr)]
    ps1
            ([Var]
    bs2,[CoreExpr]
    rs2) = [(Var, CoreExpr)] -> ([Var], [CoreExpr])
    forall a b. [(a, b)] -> ([a], [b])
    unzip [(Var, CoreExpr)]
    ps2
            env' :: RnEnv2
    env' = RnEnv2 -> [Var] -> [Var] -> RnEnv2
    rnBndrs2 RnEnv2
    env [Var]
    bs1 [Var]
    bs2

        go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Case CoreExpr
    e1 Var
    b1 Type
    t1 [Alt Var]
    a1) (Case CoreExpr
    e2 Var
    b2 Type
    t2 [Alt Var]
    a2)
          | [Alt Var] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [Alt Var]
    a1   -- See Note [Empty case alternatives] in TrieMap
          , [Alt Var] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [Alt Var]
    a2
          = do
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
               Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless Bool
    it (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> RnEnv2 -> Type -> Type -> Either SDoc ()
    goTypes [SDoc]
    ctx RnEnv2
    env Type
    t1 Type
    t2

          | Bool
    otherwise
          = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "CASE" String
    "..." ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
               Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless ([Alt Var] -> [Alt Var] -> Bool
    forall a b. [a] -> [b] -> Bool
    equalLength [Alt Var]
    a1 [Alt Var]
    a2) (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "different amount of alternatives in case"
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2
               [Either SDoc ()] -> Either SDoc ()
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, Monad m) =>
    t (m a) -> m ()
    sequence_ ([Either SDoc ()] -> Either SDoc ())
    -> [Either SDoc ()] -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ (Alt Var -> Alt Var -> Either SDoc ())
    -> [Alt Var] -> [Alt Var] -> [Either SDoc ()]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith ([SDoc]
    -> Int -> RnEnv2 -> EqEnv -> Alt Var -> Alt Var -> Either SDoc ()
    go_alt [SDoc]
    ctx Int
    lv (RnEnv2 -> Var -> Var -> RnEnv2
    rnBndr2 RnEnv2
    env Var
    b1 Var
    b2) EqEnv
    ee) [Alt Var]
    a1 [Alt Var]
    a2

        go [SDoc]
    ctx Int
    lv RnEnv2
    _ EqEnv
    _  CoreExpr
    e1 CoreExpr
    e2 = do
            Int -> String -> String -> Either SDoc ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    "FAIL" (CoreExpr -> String
    conToString CoreExpr
    e1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " =/= " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ CoreExpr -> String
    conToString CoreExpr
    e2)
            [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal terms:", CoreExpr -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoreExpr
    e1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", CoreExpr -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoreExpr
    e2]

        goCoercions :: [SDoc] -> RnEnv2 -> CoercionR -> CoercionR -> Either SDoc ()
    goCoercions [SDoc]
    ctx RnEnv2
    env CoercionR
    t1 CoercionR
    t2
            | RnEnv2 -> CoercionR -> CoercionR -> Bool
    eqCoercionX RnEnv2
    env CoercionR
    t1 CoercionR
    t2 = () -> Either SDoc ()
    forall a. a -> Either SDoc a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            | Bool
    otherwise             = [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal coercions:", CoercionR -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoercionR
    t1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", CoercionR -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoercionR
    t2 ]

        goTypes :: [SDoc] -> RnEnv2 -> Type -> Type -> Either SDoc ()
    goTypes [SDoc]
    ctx RnEnv2
    env Type
    t1 Type
    t2
            | RnEnv2 -> Type -> Type -> Bool
    eqTypeX RnEnv2
    env Type
    t1 Type
    t2 = () -> Either SDoc ()
    forall a. a -> Either SDoc a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            | Bool
    otherwise         = [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal types:", Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    t1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", Type -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Type
    t2 ]

        -----------
        go_alt :: [SDoc] -> Int -> RnEnv2 -> EqEnv -> CoreAlt -> CoreAlt -> Either SDoc ()
        go_alt :: [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> Alt Var -> Alt Var -> Either SDoc ()
    go_alt [SDoc]
    ctx Int
    lv RnEnv2
    env EqEnv
    ee (Alt AltCon
    c1 [Var]
    bs1 CoreExpr
    e1) (Alt AltCon
    c2 [Var]
    bs2 CoreExpr
    e2)
          = Int
    -> String -> String -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    "ALT" String
    "..." ((Int -> Either SDoc ()) -> Either SDoc ())
    -> (Int -> Either SDoc ()) -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    lv -> do
               Bool -> Either SDoc () -> Either SDoc ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless (AltCon
    c1 AltCon -> AltCon -> Bool
    forall a. Eq a => a -> a -> Bool
    == AltCon
    c2) (Either SDoc () -> Either SDoc ())
    -> Either SDoc () -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc -> Either SDoc ()
    forall a. [SDoc] -> SDoc -> Either SDoc a
    inequality [SDoc]
    ctx (SDoc -> Either SDoc ()) -> SDoc -> Either SDoc ()
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "inequal constructors:", AltCon -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr AltCon
    c1, String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "and", AltCon -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr AltCon
    c2 ]
               [SDoc]
    -> Int -> RnEnv2 -> EqEnv -> CoreExpr -> CoreExpr -> Either SDoc ()
    go [SDoc]
    ctx Int
    lv (RnEnv2 -> [Var] -> [Var] -> RnEnv2
    rnBndrs2 RnEnv2
    env [Var]
    bs1 [Var]
    bs2) EqEnv
    ee CoreExpr
    e1 CoreExpr
    e2

        go_tick :: RnEnv2 -> CoreTickish -> CoreTickish -> Bool
        go_tick :: RnEnv2 -> CoreTickish -> CoreTickish -> Bool
    go_tick RnEnv2
    env Breakpoint{ breakpointId :: forall (pass :: TickishPass). GenTickish pass -> Int
    breakpointId = Int
    lid, breakpointFVs :: forall (pass :: TickishPass). GenTickish pass -> [XTickishId pass]
    breakpointFVs = [XTickishId 'TickishPassCore]
    lids } Breakpoint{ breakpointId :: forall (pass :: TickishPass). GenTickish pass -> Int
    breakpointId = Int
    rid, breakpointFVs :: forall (pass :: TickishPass). GenTickish pass -> [XTickishId pass]
    breakpointFVs = [XTickishId 'TickishPassCore]
    rids }
              = Int
    lid Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    rid  Bool -> Bool -> Bool
    &&  (Var -> Var) -> [Var] -> [Var]
    forall a b. (a -> b) -> [a] -> [b]
    map (RnEnv2 -> Var -> Var
    rnOccL RnEnv2
    env) [Var]
    [XTickishId 'TickishPassCore]
    lids [Var] -> [Var] -> Bool
    forall a. Eq a => a -> a -> Bool
    == (Var -> Var) -> [Var] -> [Var]
    forall a b. (a -> b) -> [a] -> [b]
    map (RnEnv2 -> Var -> Var
    rnOccR RnEnv2
    env) [Var]
    [XTickishId 'TickishPassCore]
    rids
        go_tick RnEnv2
    _ CoreTickish
    l CoreTickish
    r = CoreTickish
    l CoreTickish -> CoreTickish -> Bool
    forall a. Eq a => a -> a -> Bool
    == CoreTickish
    r

        peelLets :: Expr a -> ([(a, Expr a)], Expr a)
    peelLets (Let (NonRec a
    v Expr a
    r) Expr a
    e) = let ([(a, Expr a)]
    xs, Expr a
    e') = Expr a -> ([(a, Expr a)], Expr a)
    peelLets Expr a
    e in ((a
    v,Expr a
    r)(a, Expr a) -> [(a, Expr a)] -> [(a, Expr a)]
    forall a. a -> [a] -> [a]
    :[(a, Expr a)]
    xs, Expr a
    e')
        peelLets (Let (Rec [(a, Expr a)]
    bs) Expr a
    e)     = let ([(a, Expr a)]
    xs, Expr a
    e') = Expr a -> ([(a, Expr a)], Expr a)
    peelLets Expr a
    e in ([(a, Expr a)]
    bs [(a, Expr a)] -> [(a, Expr a)] -> [(a, Expr a)]
    forall a. [a] -> [a] -> [a]
    ++ [(a, Expr a)]
    xs, Expr a
    e')
        peelLets Expr a
    e                    = ([], Expr a
    e)

    #if !MIN_VERSION_ghc(9,9,0) && MIN_VERSION_ghc(9,0,0)
    isUnsafeEqualityCase :: CoreExpr -> Id -> [CoreAlt] -> Maybe CoreExpr
    isUnsafeEqualityCase scrut _bndr [Alt _ _ rhs]
      | isUnsafeEqualityProof scrut = Just rhs
    isUnsafeEqualityCase _ _ _ = Nothing
    #endif

    #if !MIN_VERSION_ghc(9,2,0)
    type CoreTickish = Tickish Id
    #endif

    traceBlock :: Monad m => Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock :: forall (m :: * -> *).
    Monad m =>
    Int -> String -> String -> (Int -> m ()) -> m ()
    traceBlock Int
    lv String
    name String
    msg Int -> m ()
    action = do
        Int -> String -> String -> m ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    name String
    msg
        Int -> m ()
    action (Int
    lv Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1)
        Int -> String -> String -> m ()
    forall (m :: * -> *). Monad m => Int -> String -> String -> m ()
    tracePut Int
    lv String
    name (String -> m ()) -> String -> m ()
    forall a b. (a -> b) -> a -> b
    $ String
    msg String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " OK"

    showVars :: [(Var, a)] -> String
    showVars :: forall a. [(Var, a)] -> String
    showVars [(Var, a)]
    xs = String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    ", " [ Var -> String
    varToString Var
    x | (Var
    x, a
    _) <- [(Var, a)]
    xs ]

    pprVars :: [(Var, a)] -> SDoc
    pprVars :: forall a. [(Var, a)] -> SDoc
    pprVars = SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc
    braces (SDoc -> SDoc) -> ([(Var, a)] -> SDoc) -> [(Var, a)] -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    hsep ([SDoc] -> SDoc) -> ([(Var, a)] -> [SDoc]) -> [(Var, a)] -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((Var, a) -> SDoc) -> [(Var, a)] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map (Var -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (Var -> SDoc) -> ((Var, a) -> Var) -> (Var, a) -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Var, a) -> Var
    forall a b. (a, b) -> a
    fst)

    varToString :: Var -> String
    varToString :: Var -> String
    varToString Var
    v = OccName -> String
    occNameString (Name -> OccName
    forall name. HasOccName name => name -> OccName
    occName (Var -> Name
    tyVarName Var
    v)) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "_" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Unique -> String
    forall a. Show a => a -> String
    show (Var -> Unique
    forall a. Uniquable a => a -> Unique
    getUnique Var
    v)
    -- using tyVarName as varName is ambiguous.

    conToString :: CoreExpr -> [Char]
    conToString :: CoreExpr -> String
    conToString Var {}      = String
    "Var"
    conToString Lit {}      = String
    "Lit"
    conToString App {}      = String
    "App"
    conToString Lam {}      = String
    "Lam"
    conToString Let {}      = String
    "Let"
    conToString Case {}     = String
    "Case"
    conToString Cast {}     = String
    "Cast"
    conToString Tick {}     = String
    "Tick"
    conToString Type {}     = String
    "Type"
    conToString Coercion {} = String
    "Coercion"

    -- | Returns @True@ if the given core expression mentions no type constructor
    -- anywhere that has the given name.
    freeOfType :: Slice -> [Name] -> Maybe (Var, CoreExpr)
    freeOfType :: [(Var, CoreExpr)] -> [Name] -> Maybe (Var, CoreExpr)
    freeOfType [(Var, CoreExpr)]
    slice [Name]
    tcNs =
          ((Var, CoreExpr, [TyCon]) -> (Var, CoreExpr))
    -> Maybe (Var, CoreExpr, [TyCon]) -> Maybe (Var, CoreExpr)
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (\(Var
    a,CoreExpr
    b,[TyCon]
    _) -> (Var
    a,CoreExpr
    b))
        (Maybe (Var, CoreExpr, [TyCon]) -> Maybe (Var, CoreExpr))
    -> Maybe (Var, CoreExpr, [TyCon]) -> Maybe (Var, CoreExpr)
    forall a b. (a -> b) -> a -> b
    $ (TyCon -> Bool)
    -> [(Var, CoreExpr)] -> Maybe (Var, CoreExpr, [TyCon])
    allTyCons (\TyCon
    tc -> TyCon -> Name
    forall a. NamedThing a => a -> Name
    getName TyCon
    tc Name -> [Name] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [Name]
    tcNs) [(Var, CoreExpr)]
    slice

    -- | Check if all type constructors in a slice satisfy the given predicate.
    -- Returns the binder, expression and failing constructors triple on failure.
    allTyCons :: (TyCon -> Bool) -> Slice -> Maybe (Var, CoreExpr, [TyCon])
    allTyCons :: (TyCon -> Bool)
    -> [(Var, CoreExpr)] -> Maybe (Var, CoreExpr, [TyCon])
    allTyCons TyCon -> Bool
    ignore [(Var, CoreExpr)]
    slice =
        [(Var, CoreExpr, [TyCon])] -> Maybe (Var, CoreExpr, [TyCon])
    forall a. [a] -> Maybe a
    listToMaybe
            [(Var
    v, CoreExpr
    e, [TyCon] -> [TyCon]
    forall a. Eq a => [a] -> [a]
    nub [TyCon]
    tcs) | (Var
    v, CoreExpr
    e) <- [(Var, CoreExpr)]
    slice, let tcs :: [TyCon]
    tcs = CoreExpr -> [TyCon]
    go CoreExpr
    e, Bool -> Bool
    not ([TyCon] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [TyCon]
    tcs)]
      where
        goV :: Var -> [TyCon]
    goV Var
    v = Type -> [TyCon]
    goT (Var -> Type
    varType Var
    v)

        go :: CoreExpr -> [TyCon]
    go (Var Var
    v)           = Var -> [TyCon]
    goV Var
    v
        go (Lit Literal
    _)           = []
        go (App CoreExpr
    e CoreExpr
    a)         = CoreExpr -> [TyCon]
    go CoreExpr
    e [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ CoreExpr -> [TyCon]
    go CoreExpr
    a
        go (Lam Var
    b CoreExpr
    e)         = Var -> [TyCon]
    goV Var
    b [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ CoreExpr -> [TyCon]
    go CoreExpr
    e
        go (Let Bind Var
    bind CoreExpr
    body)   = ((Var, CoreExpr) -> [TyCon]) -> [(Var, CoreExpr)] -> [TyCon]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (Var, CoreExpr) -> [TyCon]
    goB ([Bind Var] -> [(Var, CoreExpr)]
    forall b. [Bind b] -> [(b, Expr b)]
    flattenBinds [Bind Var
    bind]) [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ CoreExpr -> [TyCon]
    go CoreExpr
    body
        go (Case CoreExpr
    s Var
    b Type
    _ [Alt Var]
    alts) = CoreExpr -> [TyCon]
    go CoreExpr
    s [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ Var -> [TyCon]
    goV Var
    b [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ (Alt Var -> [TyCon]) -> [Alt Var] -> [TyCon]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Alt Var -> [TyCon]
    goA [Alt Var]
    alts
        go (Cast CoreExpr
    e CoercionR
    _)        = CoreExpr -> [TyCon]
    go CoreExpr
    e
        go (Tick CoreTickish
    _ CoreExpr
    e)        = CoreExpr -> [TyCon]
    go CoreExpr
    e
        go (Type Type
    t)          = (Type -> [TyCon]
    goT Type
    t)
        go (Coercion CoercionR
    _)      = []

        goB :: (Var, CoreExpr) -> [TyCon]
    goB (Var
    b, CoreExpr
    e) = Var -> [TyCon]
    goV Var
    b [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ CoreExpr -> [TyCon]
    go CoreExpr
    e

        goA :: Alt Var -> [TyCon]
    goA (Alt AltCon
    _ [Var]
    pats CoreExpr
    e) = (Var -> [TyCon]) -> [Var] -> [TyCon]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Var -> [TyCon]
    goV [Var]
    pats [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ CoreExpr -> [TyCon]
    go CoreExpr
    e

        goT :: Type -> [TyCon]
    goT (TyVarTy Var
    _)      = []
        goT (AppTy Type
    t1 Type
    t2)    = Type -> [TyCon]
    goT Type
    t1 [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ Type -> [TyCon]
    goT Type
    t2
        goT (TyConApp TyCon
    tc [Type]
    ts) = [TyCon
    tc | Bool -> Bool
    not (TyCon -> Bool
    ignore TyCon
    tc)] [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ (Type -> [TyCon]) -> [Type] -> [TyCon]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Type -> [TyCon]
    goT [Type]
    ts
                               -- ↑ This is the crucial bit
        goT (ForAllTy ForAllTyBinder
    _ Type
    t)   = Type -> [TyCon]
    goT Type
    t
    #if MIN_VERSION_GLASGOW_HASKELL(8,2,0,0)
        goT (FunTy
    #if MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
                   FunTyFlag
    _
    #endif
    # if MIN_VERSION_GLASGOW_HASKELL(8,9,0,0)
                   Type
    _
    # endif
                     Type
    t1 Type
    t2)  = Type -> [TyCon]
    goT Type
    t1 [TyCon] -> [TyCon] -> [TyCon]
    forall a. [a] -> [a] -> [a]
    ++ Type -> [TyCon]
    goT Type
    t2
    #endif
        goT (LitTy TyLit
    _)        = []
        goT (CastTy Type
    t CoercionR
    _)     = Type -> [TyCon]
    goT Type
    t
        goT (CoercionTy CoercionR
    _)   = []
    --
    -- | Returns @True@ if the given core expression mentions no term variable
    -- anywhere that has the given name.
    freeOfTerm :: Slice -> [Name] -> Maybe (Var, CoreExpr)
    freeOfTerm :: [(Var, CoreExpr)] -> [Name] -> Maybe (Var, CoreExpr)
    freeOfTerm [(Var, CoreExpr)]
    slice [Name]
    needles = [(Var, CoreExpr)] -> Maybe (Var, CoreExpr)
    forall a. [a] -> Maybe a
    listToMaybe [ (Var
    v,CoreExpr
    e) | (Var
    v,CoreExpr
    e) <- [(Var, CoreExpr)]
    slice, Bool -> Bool
    not (CoreExpr -> Bool
    forall b. Expr b -> Bool
    go CoreExpr
    e) ]
      where
        isNeedle :: Name -> Bool
    isNeedle Name
    n = Name
    n Name -> [Name] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Name]
    needles

        goV :: Var -> Bool
    goV Var
    v | Name -> Bool
    isNeedle (Var -> Name
    Var.varName Var
    v)  = Bool
    False
              | Just DataCon
    dc <- Var -> Maybe DataCon
    isDataConId_maybe Var
    v
              , Name -> Bool
    isNeedle (DataCon -> Name
    dataConName DataCon
    dc) = Bool
    False
              | Bool
    otherwise                 = Bool
    True

        go :: Expr b -> Bool
    go (Var Var
    v)           = Var -> Bool
    goV Var
    v
        go (Lit Literal
    _ )          = Bool
    True
        go (App Expr b
    e Expr b
    a)         = Expr b -> Bool
    go Expr b
    e Bool -> Bool -> Bool
    && Expr b -> Bool
    go Expr b
    a
        go (Lam b
    _ Expr b
    e)         = Expr b -> Bool
    go Expr b
    e
        go (Let Bind b
    bind Expr b
    body)   = ((b, Expr b) -> Bool) -> [(b, Expr b)] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (b, Expr b) -> Bool
    goB ([Bind b] -> [(b, Expr b)]
    forall b. [Bind b] -> [(b, Expr b)]
    flattenBinds [Bind b
    bind]) Bool -> Bool -> Bool
    && Expr b -> Bool
    go Expr b
    body
        go (Case Expr b
    s b
    _ Type
    _ [Alt b]
    alts) = Expr b -> Bool
    go Expr b
    s Bool -> Bool -> Bool
    && (Alt b -> Bool) -> [Alt b] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Alt b -> Bool
    goA [Alt b]
    alts
        go (Cast Expr b
    e CoercionR
    _)        = Expr b -> Bool
    go Expr b
    e
        go (Tick CoreTickish
    _ Expr b
    e)        = Expr b -> Bool
    go Expr b
    e
        go (Type Type
    _)          = Bool
    True
        go (Coercion CoercionR
    _)      = Bool
    True

        goB :: (b, Expr b) -> Bool
    goB (b
    _, Expr b
    e) = Expr b -> Bool
    go Expr b
    e

        goA :: Alt b -> Bool
    goA (Alt AltCon
    ac [b]
    _ Expr b
    e) = AltCon -> Bool
    goAltCon AltCon
    ac Bool -> Bool -> Bool
    && Expr b -> Bool
    go Expr b
    e

        goAltCon :: AltCon -> Bool
    goAltCon (DataAlt DataCon
    dc) | Name -> Bool
    isNeedle (DataCon -> Name
    dataConName DataCon
    dc) = Bool
    False
        goAltCon AltCon
    _ = Bool
    True

    -- | True if the given variable binding does not allocate, if called fully
    -- satisfied.
    --
    -- It currently does not look through function calls, which of course could
    -- allocate. It should probably at least look through local function calls.
    --
    -- The variable is important to know the arity of the function.
    doesNotAllocate :: Slice -> Maybe (Var, CoreExpr)
    doesNotAllocate :: [(Var, CoreExpr)] -> Maybe (Var, CoreExpr)
    doesNotAllocate [(Var, CoreExpr)]
    slice = [(Var, CoreExpr)] -> Maybe (Var, CoreExpr)
    forall a. [a] -> Maybe a
    listToMaybe [ (Var
    v,CoreExpr
    e) | (Var
    v,CoreExpr
    e) <- [(Var, CoreExpr)]
    slice, Bool -> Bool
    not (Int -> CoreExpr -> Bool
    go (Var -> Int
    idArity Var
    v) CoreExpr
    e) ]
      where
        go :: Int -> CoreExpr -> Bool
    go Int
    _ (Var Var
    v)
          | Var -> Bool
    isDataConWorkId Var
    v, Var -> Int
    idArity Var
    v Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0 = Bool
    False
        go Int
    a (Var Var
    v)                         = Int
    a Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Var -> Int
    idArity Var
    v
        go Int
    _ (Lit Literal
    _ )                        = Bool
    True
        go Int
    a (App CoreExpr
    e CoreExpr
    arg) | CoreExpr -> Bool
    forall b. Expr b -> Bool
    isTypeArg CoreExpr
    arg     = Int -> CoreExpr -> Bool
    go Int
    a CoreExpr
    e
        go Int
    a (App CoreExpr
    e CoreExpr
    arg)                     = Int -> CoreExpr -> Bool
    go (Int
    aInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    1) CoreExpr
    e Bool -> Bool -> Bool
    && CoreExpr -> Bool
    goArg CoreExpr
    arg
        go Int
    a (Lam Var
    b CoreExpr
    e) | Var -> Bool
    isTyVar Var
    b           = Int -> CoreExpr -> Bool
    go Int
    a CoreExpr
    e
        go Int
    0 (Lam Var
    _ CoreExpr
    _)                       = Bool
    False
        go Int
    a (Lam Var
    _ CoreExpr
    e)                       = Int -> CoreExpr -> Bool
    go (Int
    aInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) CoreExpr
    e
        go Int
    a (Let Bind Var
    bind CoreExpr
    body)                 = ((Var, CoreExpr) -> Bool) -> [(Var, CoreExpr)] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Var, CoreExpr) -> Bool
    goB ([Bind Var] -> [(Var, CoreExpr)]
    forall b. [Bind b] -> [(b, Expr b)]
    flattenBinds [Bind Var
    bind]) Bool -> Bool -> Bool
    && Int -> CoreExpr -> Bool
    go Int
    a CoreExpr
    body
        go Int
    a (Case CoreExpr
    s Var
    _ Type
    _ [Alt Var]
    alts)               = Int -> CoreExpr -> Bool
    go Int
    0 CoreExpr
    s Bool -> Bool -> Bool
    && (Alt Var -> Bool) -> [Alt Var] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Int -> Alt Var -> Bool
    goA Int
    a) [Alt Var]
    alts
        go Int
    a (Cast CoreExpr
    e CoercionR
    _)                      = Int -> CoreExpr -> Bool
    go Int
    a CoreExpr
    e
        go Int
    a (Tick CoreTickish
    _ CoreExpr
    e)                      = Int -> CoreExpr -> Bool
    go Int
    a CoreExpr
    e
        go Int
    _ (Type Type
    _)                        = Bool
    True
        go Int
    _ (Coercion CoercionR
    _)                    = Bool
    True

        goArg :: CoreExpr -> Bool
    goArg CoreExpr
    e | CoreExpr -> Bool
    exprIsTrivial CoreExpr
    e             = Int -> CoreExpr -> Bool
    go Int
    0 CoreExpr
    e
                | HasDebugCallStack => Type -> Bool
    Type -> Bool
    isUnliftedType (HasDebugCallStack => CoreExpr -> Type
    CoreExpr -> Type
    exprType CoreExpr
    e) = Int -> CoreExpr -> Bool
    go Int
    0 CoreExpr
    e
                | Bool
    otherwise                   = Bool
    False

        goB :: (Var, CoreExpr) -> Bool
    goB (Var
    b, CoreExpr
    e)
    #if MIN_VERSION_GLASGOW_HASKELL(8,2,0,0)
            | Var -> Bool
    isJoinId Var
    b                = Int -> CoreExpr -> Bool
    go (Var -> Int
    idArity Var
    b) CoreExpr
    e
    #endif
            -- Not sure when a local function definition allocates…
            | Type -> Bool
    isFunTy (Var -> Type
    idType Var
    b)        = Int -> CoreExpr -> Bool
    go (Var -> Int
    idArity Var
    b) CoreExpr
    e
            | HasDebugCallStack => Type -> Bool
    Type -> Bool
    isUnliftedType (Var -> Type
    idType Var
    b) = Int -> CoreExpr -> Bool
    go (Var -> Int
    idArity Var
    b) CoreExpr
    e
            | Bool
    otherwise                 = Bool
    False
            -- A let binding allocates if any variable is not a join point and not
            -- unlifted

        goA :: Int -> Alt Var -> Bool
    goA Int
    a (Alt AltCon
    _ [Var]
    _ CoreExpr
    e) = Int -> CoreExpr -> Bool
    go Int
    a CoreExpr
    e

    doesNotContainTypeClasses :: Slice -> [Name] -> Maybe (Var, CoreExpr, [TyCon])
    doesNotContainTypeClasses :: [(Var, CoreExpr)] -> [Name] -> Maybe (Var, CoreExpr, [TyCon])
    doesNotContainTypeClasses [(Var, CoreExpr)]
    slice [Name]
    tcNs
        = (TyCon -> Bool)
    -> [(Var, CoreExpr)] -> Maybe (Var, CoreExpr, [TyCon])
    allTyCons (\TyCon
    tc -> Bool -> Bool
    not (TyCon -> Bool
    isClassTyCon TyCon
    tc) Bool -> Bool -> Bool
    || Name -> Bool
    isCTupleTyConName (TyCon -> Name
    forall a. NamedThing a => a -> Name
    getName TyCon
    tc) Bool -> Bool -> Bool
    || (Name -> Bool) -> [Name] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (TyCon -> Name
    forall a. NamedThing a => a -> Name
    getName TyCon
    tc Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) [Name]
    tcNs) [(Var, CoreExpr)]
    slice

    rename :: InScopeSet -> [(Var, Var)] -> CoreExpr -> CoreExpr
    rename :: InScopeSet -> [(Var, Var)] -> CoreExpr -> CoreExpr
    rename InScopeSet
    iss [(Var, Var)]
    rn = Subst -> CoreExpr -> CoreExpr
    substExpr' Subst
    sub where
        -- convert RnEnv2 to Subst
        -- here we forget about tyvars and covars, but mostly this is good enough.
        sub :: Subst
    sub = InScopeSet -> [(Var, CoreExpr)] -> Subst
    mkOpenSubst InScopeSet
    iss [ (Var
    v1, if Var -> Bool
    isTyVar Var
    v2 then Type -> CoreExpr
    forall b. Type -> Expr b
    Type (Var -> Type
    mkTyVarTy Var
    v2) else if Var -> Bool
    isCoVar Var
    v2 then CoercionR -> CoreExpr
    forall b. CoercionR -> Expr b
    Coercion (Var -> CoercionR
    mkCoVarCo Var
    v2) else Var -> CoreExpr
    forall b. Var -> Expr b
    Var Var
    v2 ) | (Var
    v1, Var
    v2) <- [(Var, Var)]
    rn]

    #if MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
        substExpr' :: Subst -> CoreExpr -> CoreExpr
    substExpr' = HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr
    #else
        substExpr' = substExpr empty
    #endif