content: {-# LANGUAGE PatternSynonyms #-}
  {-# LANGUAGE ViewPatterns #-}
  module GHC.Tc.Types.TH (
      SpliceType(..)
    , SpliceOrBracket(..)
    , ThLevel(.., TypedBrack, UntypedBrack)
    , PendingStuff(..)
    , ThLevelIndex
    , topLevel
    , topAnnLevel
    , topSpliceLevel
    , thLevelIndex
    , topLevelIndex
    , spliceLevelIndex
    , quoteLevelIndex
    , thLevelIndexFromImportLevel
    ) where
  
  import GHC.Prelude
  import GHCi.RemoteTypes
  import qualified GHC.Boot.TH.Monad  as TH
  import GHC.Tc.Types.Evidence
  import GHC.Utils.Outputable
  import GHC.Tc.Types.TcRef
  import GHC.Tc.Types.Constraint
  import GHC.Hs.Expr ( PendingTcSplice, PendingRnSplice )
  import GHC.Types.ThLevelIndex
  
  ---------------------------
  -- Template Haskell stages and levels
  ---------------------------
  
  data SpliceType = Typed | Untyped
  data SpliceOrBracket = IsSplice | IsBracket
  
  data ThLevel    -- 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:  wrap current stage in Splice
    = Splice SpliceType ThLevel -- Inside a splice
  
    | 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 = 0
  
    | Brack                       -- Inside brackets
        ThLevel                   --  Enclosing level
        PendingStuff
  
  data PendingStuff
    = RnPending                     -- Renaming the inside of a 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`.
  
  isTypedPending :: PendingStuff -> Bool
  isTypedPending (RnPending _) = False
  isTypedPending (RnPendingTyped) = True
  isTypedPending (TcPending _ _ _) = True
  
  pattern UntypedBrack :: ThLevel -> TcRef [PendingRnSplice] -> ThLevel
  pattern UntypedBrack lvl tc_ref = Brack lvl (RnPending tc_ref)
  pattern TypedBrack :: ThLevel -> ThLevel
  pattern TypedBrack lvl <- Brack lvl (isTypedPending -> True)
  
  topLevel, topAnnLevel, topSpliceLevel :: ThLevel
  topLevel       = Comp
  topAnnLevel    = Splice Untyped Comp
  topSpliceLevel = Splice Untyped Comp
  
  
  instance Outputable ThLevel where
     ppr (Splice _ s)  = text "Splice" <> parens (ppr s)
     ppr (RunSplice _) = text "RunSplice"
     ppr Comp          = text "Comp"
     ppr (Brack s _) = text "Brack" <> parens (ppr s)
  
  
  thLevelIndex :: ThLevel -> ThLevelIndex
  thLevelIndex (Splice _ s)  = decThLevelIndex (thLevelIndex s)
  thLevelIndex Comp          = topLevelIndex
  thLevelIndex (Brack s _) = incThLevelIndex (thLevelIndex s)
  thLevelIndex (RunSplice _) = thLevelIndex (Splice Untyped Comp) -- previously: panic "thLevel: called when running a splice"
                          -- See Note [RunSplice ThLevel].
  
  
  {- Note [RunSplice ThLevel]
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  The 'RunSplice' level 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.
  
  -}
  
  