module GHC.Tc.Types.LclEnv (
    TcLclEnv(..)
  , TcLclCtxt(..)
  , modifyLclCtxt

  , getLclEnvArrowCtxt
  , getLclEnvThBndrs
  , getLclEnvTypeEnv
  , getLclEnvBinderStack
  , getLclEnvErrCtxt
  , getLclEnvLoc
  , getLclEnvRdrEnv
  , getLclEnvTcLevel
  , getLclEnvThStage
  , setLclEnvTcLevel
  , setLclEnvLoc
  , setLclEnvRdrEnv
  , setLclEnvBinderStack
  , setLclEnvErrCtxt
  , setLclEnvThStage
  , setLclEnvTypeEnv
  , modifyLclEnvTcLevel

  , lclEnvInGeneratedCode

  , addLclEnvErrCtxt

  , ArrowCtxt(..)
  , ThBindEnv
  , TcTypeEnv
) where

import GHC.Prelude

import GHC.Tc.Utils.TcType ( TcLevel )
import GHC.Tc.Errors.Types ( TcRnMessage )

import GHC.Core.UsageEnv ( UsageEnv )

import GHC.Types.Name.Reader ( LocalRdrEnv )
import GHC.Types.Name.Env ( NameEnv )
import GHC.Types.SrcLoc ( RealSrcSpan )
import GHC.Types.Basic ( TopLevelFlag )

import GHC.Types.Error ( Messages )

import GHC.Tc.Types.BasicTypes
import GHC.Tc.Types.TH
import GHC.Tc.Types.TcRef
import GHC.Tc.Types.ErrCtxt
import GHC.Tc.Types.Constraint ( WantedConstraints )

{-
************************************************************************
*                                                                      *
                The local typechecker environment
*                                                                      *
************************************************************************

Note [The Global-Env/Local-Env story]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
During type checking, we keep in the tcg_type_env
        * All types and classes
        * All Ids derived from types and classes (constructors, selectors)

At the end of type checking, we zonk the local bindings,
and as we do so we add to the tcg_type_env
        * Locally defined top-level Ids

Why?  Because they are now Ids not TcIds.  This final GlobalEnv is
        a) fed back (via the knot) to typechecking the
           unfoldings of interface signatures
        b) used in the ModDetails of this module
-}

data TcLclEnv           -- Changes as we move inside an expression
                        -- Discarded after typecheck/rename; not passed on to desugarer
  = TcLclEnv {
        -- The part that we sometimes restore using `restoreLclEnv`.
        TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt    :: !TcLclCtxt,

        -- These are exactly the parts of TcLclEnv which are not set by `restoreLclEnv`.

        TcLclEnv -> TcRef UsageEnv
tcl_usage :: TcRef UsageEnv, -- Required multiplicity of bindings is accumulated here.
        TcLclEnv -> TcRef WantedConstraints
tcl_lie  :: TcRef WantedConstraints,    -- Place to accumulate type constraints
        TcLclEnv -> TcRef (Messages TcRnMessage)
tcl_errs :: TcRef (Messages TcRnMessage)     -- Place to accumulate diagnostics
    }

data TcLclCtxt
  = TcLclCtxt {
        TcLclCtxt -> RealSrcSpan
tcl_loc        :: RealSrcSpan,     -- Source span
        TcLclCtxt -> [ErrCtxt]
tcl_ctxt       :: [ErrCtxt],       -- Error context, innermost on top
        TcLclCtxt -> Bool
tcl_in_gen_code :: Bool,           -- See Note [Rebindable syntax and HsExpansion]
        TcLclCtxt -> TcLevel
tcl_tclvl      :: TcLevel,
        TcLclCtxt -> TcBinderStack
tcl_bndrs      :: TcBinderStack,   -- Used for reporting relevant bindings,
                                           -- and for tidying type

        TcLclCtxt -> LocalRdrEnv
tcl_rdr :: LocalRdrEnv,         -- Local name envt
                -- Maintained during renaming, of course, but also during
                -- type checking, solely so that when renaming a Template-Haskell
                -- splice we have the right environment for the renamer.
                --
                --   Does *not* include global name envt; may shadow it
                --   Includes both ordinary variables and type variables;
                --   they are kept distinct because tyvar have a different
                --   occurrence constructor (Name.TvOcc)
                -- We still need the unsullied global name env so that
                --   we can look up record field names


        TcLclCtxt -> ThStage
tcl_th_ctxt    :: ThStage,         -- Template Haskell context
        TcLclCtxt -> ThBindEnv
tcl_th_bndrs   :: ThBindEnv,       -- and binder info
            -- The ThBindEnv records the TH binding level of in-scope Names
            -- defined in this module (not imported)
            -- We can't put this info in the TypeEnv because it's needed
            -- (and extended) in the renamer, for untyped splices

        TcLclCtxt -> ArrowCtxt
tcl_arrow_ctxt :: ArrowCtxt,       -- Arrow-notation context

        TcLclCtxt -> TcTypeEnv
tcl_env  :: TcTypeEnv    -- The local type environment:
                                 -- Ids and TyVars defined in this module

    }

getLclEnvThStage :: TcLclEnv -> ThStage
getLclEnvThStage :: TcLclEnv -> ThStage
getLclEnvThStage = TcLclCtxt -> ThStage
tcl_th_ctxt (TcLclCtxt -> ThStage)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> ThStage
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

setLclEnvThStage :: ThStage -> TcLclEnv -> TcLclEnv
setLclEnvThStage :: ThStage -> TcLclEnv -> TcLclEnv
setLclEnvThStage ThStage
s = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_th_ctxt = s })

getLclEnvThBndrs :: TcLclEnv -> ThBindEnv
getLclEnvThBndrs :: TcLclEnv -> ThBindEnv
getLclEnvThBndrs = TcLclCtxt -> ThBindEnv
tcl_th_bndrs (TcLclCtxt -> ThBindEnv)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> ThBindEnv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

getLclEnvArrowCtxt :: TcLclEnv -> ArrowCtxt
getLclEnvArrowCtxt :: TcLclEnv -> ArrowCtxt
getLclEnvArrowCtxt = TcLclCtxt -> ArrowCtxt
tcl_arrow_ctxt (TcLclCtxt -> ArrowCtxt)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> ArrowCtxt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

getLclEnvTypeEnv :: TcLclEnv -> TcTypeEnv
getLclEnvTypeEnv :: TcLclEnv -> TcTypeEnv
getLclEnvTypeEnv = TcLclCtxt -> TcTypeEnv
tcl_env (TcLclCtxt -> TcTypeEnv)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> TcTypeEnv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

setLclEnvTypeEnv :: TcTypeEnv -> TcLclEnv -> TcLclEnv
setLclEnvTypeEnv :: TcTypeEnv -> TcLclEnv -> TcLclEnv
setLclEnvTypeEnv TcTypeEnv
ty_env = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_env = ty_env})

setLclEnvTcLevel :: TcLevel -> TcLclEnv -> TcLclEnv
setLclEnvTcLevel :: TcLevel -> TcLclEnv -> TcLclEnv
setLclEnvTcLevel TcLevel
lvl = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env {tcl_tclvl = lvl })

modifyLclEnvTcLevel :: (TcLevel -> TcLevel) -> TcLclEnv -> TcLclEnv
modifyLclEnvTcLevel :: (TcLevel -> TcLevel) -> TcLclEnv -> TcLclEnv
modifyLclEnvTcLevel TcLevel -> TcLevel
f = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_tclvl = f (tcl_tclvl env)})

getLclEnvTcLevel :: TcLclEnv -> TcLevel
getLclEnvTcLevel :: TcLclEnv -> TcLevel
getLclEnvTcLevel = TcLclCtxt -> TcLevel
tcl_tclvl (TcLclCtxt -> TcLevel)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> TcLevel
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

setLclEnvLoc :: RealSrcSpan -> TcLclEnv -> TcLclEnv
setLclEnvLoc :: RealSrcSpan -> TcLclEnv -> TcLclEnv
setLclEnvLoc RealSrcSpan
loc = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
lenv -> TcLclCtxt
lenv { tcl_loc = loc })

getLclEnvLoc :: TcLclEnv -> RealSrcSpan
getLclEnvLoc :: TcLclEnv -> RealSrcSpan
getLclEnvLoc = TcLclCtxt -> RealSrcSpan
tcl_loc (TcLclCtxt -> RealSrcSpan)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> RealSrcSpan
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

getLclEnvErrCtxt :: TcLclEnv -> [ErrCtxt]
getLclEnvErrCtxt :: TcLclEnv -> [ErrCtxt]
getLclEnvErrCtxt = TcLclCtxt -> [ErrCtxt]
tcl_ctxt (TcLclCtxt -> [ErrCtxt])
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> [ErrCtxt]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

setLclEnvErrCtxt :: [ErrCtxt] -> TcLclEnv -> TcLclEnv
setLclEnvErrCtxt :: [ErrCtxt] -> TcLclEnv -> TcLclEnv
setLclEnvErrCtxt [ErrCtxt]
ctxt = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_ctxt = ctxt })

addLclEnvErrCtxt :: ErrCtxt -> TcLclEnv -> TcLclEnv
addLclEnvErrCtxt :: ErrCtxt -> TcLclEnv -> TcLclEnv
addLclEnvErrCtxt ErrCtxt
ctxt = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_ctxt = ctxt : (tcl_ctxt env) })

lclEnvInGeneratedCode :: TcLclEnv -> Bool
lclEnvInGeneratedCode :: TcLclEnv -> Bool
lclEnvInGeneratedCode = TcLclCtxt -> Bool
tcl_in_gen_code (TcLclCtxt -> Bool) -> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

getLclEnvBinderStack :: TcLclEnv -> TcBinderStack
getLclEnvBinderStack :: TcLclEnv -> TcBinderStack
getLclEnvBinderStack = TcLclCtxt -> TcBinderStack
tcl_bndrs (TcLclCtxt -> TcBinderStack)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> TcBinderStack
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

setLclEnvBinderStack :: TcBinderStack -> TcLclEnv -> TcLclEnv
setLclEnvBinderStack :: TcBinderStack -> TcLclEnv -> TcLclEnv
setLclEnvBinderStack TcBinderStack
stack = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_bndrs = stack })

getLclEnvRdrEnv :: TcLclEnv -> LocalRdrEnv
getLclEnvRdrEnv :: TcLclEnv -> LocalRdrEnv
getLclEnvRdrEnv = TcLclCtxt -> LocalRdrEnv
tcl_rdr (TcLclCtxt -> LocalRdrEnv)
-> (TcLclEnv -> TcLclCtxt) -> TcLclEnv -> LocalRdrEnv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt

setLclEnvRdrEnv :: LocalRdrEnv -> TcLclEnv -> TcLclEnv
setLclEnvRdrEnv :: LocalRdrEnv -> TcLclEnv -> TcLclEnv
setLclEnvRdrEnv LocalRdrEnv
rdr_env = (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt (\TcLclCtxt
env -> TcLclCtxt
env { tcl_rdr = rdr_env })

modifyLclCtxt :: (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt :: (TcLclCtxt -> TcLclCtxt) -> TcLclEnv -> TcLclEnv
modifyLclCtxt TcLclCtxt -> TcLclCtxt
upd TcLclEnv
env =
  let !res :: TcLclCtxt
res = TcLclCtxt -> TcLclCtxt
upd (TcLclEnv -> TcLclCtxt
tcl_lcl_ctxt TcLclEnv
env)
  in TcLclEnv
env { tcl_lcl_ctxt = res }



type TcTypeEnv = NameEnv TcTyThing

type ThBindEnv = NameEnv (TopLevelFlag, ThLevel)
   -- Domain = all Ids bound in this module (ie not imported)
   -- The TopLevelFlag tells if the binding is syntactically top level.
   -- We need to know this, because the cross-stage persistence story allows
   -- cross-stage at arbitrary types if the Id is bound at top level.
   --
   -- Nota bene: a ThLevel of 'outerLevel' is *not* the same as being
   -- bound at top level!  See Note [Template Haskell levels] in GHC.Tc.Gen.Splice

---------------------------
-- Arrow-notation context
---------------------------

{- Note [Escaping the arrow scope]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In arrow notation, a variable bound by a proc (or enclosed let/kappa)
is not in scope to the left of an arrow tail (-<) or the head of (|..|).
For example

        proc x -> (e1 -< e2)

Here, x is not in scope in e1, but it is in scope in e2.  This can get
a bit complicated:

        let x = 3 in
        proc y -> (proc z -> e1) -< e2

Here, x and z are in scope in e1, but y is not.

We implement this by
recording the environment when passing a proc (using newArrowScope),
and returning to that (using escapeArrowScope) on the left of -< and the
head of (|..|).

All this can be dealt with by the *renamer*. But the type checker needs
to be involved too.  Example (arrowfail001)
  class Foo a where foo :: a -> ()
  data Bar = forall a. Foo a => Bar a
  get :: Bar -> ()
  get = proc x -> case x of Bar a -> foo -< a
Here the call of 'foo' gives rise to a (Foo a) constraint that should not
be captured by the pattern match on 'Bar'.  Rather it should join the
constraints from further out.  So we must capture the constraint bag
from further out in the ArrowCtxt that we push inwards.
-}

data ArrowCtxt   -- Note [Escaping the arrow scope]
  = NoArrowCtxt
  | ArrowCtxt LocalRdrEnv (TcRef WantedConstraints)