    module GHC.Tc.Types.TH (
        SpliceType(..)
      , SpliceOrBracket(..)
      , ThStage(..)
      , PendingStuff(..)
      , ThLevel
      , topStage
      , topAnnStage
      , topSpliceStage
      , thLevel
      , impLevel
      , outerLevel
      ) where

    import GHCi.RemoteTypes
    import qualified GHC.Internal.TH.Syntax as TH
    import GHC.Tc.Types.Evidence
    import GHC.Utils.Outputable
    import GHC.Prelude
    import GHC.Tc.Types.TcRef
    import GHC.Tc.Types.Constraint
    import GHC.Hs.Expr ( PendingTcSplice, PendingRnSplice )

    ---------------------------
    -- Template Haskell stages and levels
    ---------------------------

    data SpliceType = Typed | Untyped
    data SpliceOrBracket = IsSplice | IsBracket

    data ThStage    -- See Note [Template Haskell state diagram]
                    -- and Note [Template Haskell levels] in GHC.Tc.Gen.Splice
        -- Start at:   Comp
        -- At bracket: wrap current stage in Brack
        -- At splice:  currently Brack: return to previous stage
        --             currently Comp/Splice: compile and run
      = Splice SpliceType -- Inside a top-level splice
                          -- This code will be run *at compile time*;
                          --   the result replaces the splice
                          -- Binding level = 0

      | RunSplice (TcRef [ForeignRef (TH.Q ())])
          -- Set when running a splice, i.e. NOT when renaming or typechecking the
          -- Haskell code for the splice. See Note [RunSplice ThLevel].
          --
          -- Contains a list of mod finalizers collected while executing the splice.
          --
          -- 'addModFinalizer' inserts finalizers here, and from here they are taken
          -- to construct an @HsSpliced@ annotation for untyped splices. See Note
          -- [Delaying modFinalizers in untyped splices] in GHC.Rename.Splice.
          --
          -- For typed splices, the typechecker takes finalizers from here and
          -- inserts them in the list of finalizers in the global environment.
          --
          -- See Note [Collecting modFinalizers in typed splices] in "GHC.Tc.Gen.Splice".

      | Comp        -- Ordinary Haskell code
                    -- Binding level = 1

      | Brack                       -- Inside brackets
          ThStage                   --   Enclosing stage
          PendingStuff

    data PendingStuff
      = RnPendingUntyped              -- Renaming the inside of an *untyped* bracket
          (TcRef [PendingRnSplice])   -- Pending splices in here

      | RnPendingTyped                -- Renaming the inside of a *typed* bracket

      | TcPending                     -- Typechecking the inside of a typed bracket
          (TcRef [PendingTcSplice])   --   Accumulate pending splices here
          (TcRef WantedConstraints)   --     and type constraints here
          QuoteWrapper                -- A type variable and evidence variable
                                      -- for the overall monad of
                                      -- the bracket. Splices are checked
                                      -- against this monad. The evidence
                                      -- variable is used for desugaring
                                      -- `lift`.

    topStage, topAnnStage, topSpliceStage :: ThStage
    topStage :: ThStage
    topStage       = ThStage
    Comp
    topAnnStage :: ThStage
    topAnnStage    = SpliceType -> ThStage
    Splice SpliceType
    Untyped
    topSpliceStage :: ThStage
    topSpliceStage = SpliceType -> ThStage
    Splice SpliceType
    Untyped

    instance Outputable ThStage where
       ppr :: ThStage -> SDoc
    ppr (Splice SpliceType
    _)    = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Splice"
       ppr (RunSplice TcRef [ForeignRef (Q ())]
    _) = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "RunSplice"
       ppr ThStage
    Comp          = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Comp"
       ppr (Brack ThStage
    s PendingStuff
    _)   = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Brack" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc
    parens (ThStage -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr ThStage
    s)

    type ThLevel = Int
        -- NB: see Note [Template Haskell levels] in GHC.Tc.Gen.Splice
        -- Incremented when going inside a bracket,
        -- decremented when going inside a splice
        -- NB: ThLevel is one greater than the 'n' in Fig 2 of the
        --     original "Template meta-programming for Haskell" paper

    impLevel, outerLevel :: ThLevel
    impLevel :: ThLevel
    impLevel = ThLevel
    0    -- Imported things; they can be used inside a top level splice
    outerLevel :: ThLevel
    outerLevel = ThLevel
    1  -- Things defined outside brackets

    thLevel :: ThStage -> ThLevel
    thLevel :: ThStage -> ThLevel
    thLevel (Splice SpliceType
    _)    = ThLevel
    0
    thLevel ThStage
    Comp          = ThLevel
    1
    thLevel (Brack ThStage
    s PendingStuff
    _)   = ThStage -> ThLevel
    thLevel ThStage
    s ThLevel -> ThLevel -> ThLevel
    forall a. Num a => a -> a -> a
    + ThLevel
    1
    thLevel (RunSplice TcRef [ForeignRef (Q ())]
    _) = ThLevel
    0 -- previously: panic "thLevel: called when running a splice"
                            -- See Note [RunSplice ThLevel].

    {- Note [RunSplice ThLevel]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The 'RunSplice' stage is set when executing a splice, and only when running a
    splice. In particular it is not set when the splice is renamed or typechecked.

    However, this is not true. `reifyInstances` for example does rename the given type,
    and these types may contain variables (#9262 allow free variables in reifyInstances).
    Therefore here we assume that thLevel (RunSplice _) = 0.
    Proper fix would probably require renaming argument `reifyInstances` separately prior
    to evaluation of the overall splice.

    'RunSplice' is needed to provide a reference where 'addModFinalizer' can insert
    the finalizer (see Note [Delaying modFinalizers in untyped splices]), and
    'addModFinalizer' runs when doing Q things. Therefore, It doesn't make sense to
    set 'RunSplice' when renaming or typechecking the splice, where 'Splice',
    'Brack' or 'Comp' are used instead.

    -}