%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
\section{@Vars@: Variables}

\begin{code}
module Var (
	Var, 
	varName, varUnique, 
	setVarName, setVarUnique, setVarOcc,

	-- TyVars
	TyVar, mkTyVar, mkTcTyVar,
	tyVarName, tyVarKind,
	setTyVarName, setTyVarUnique,
	tcTyVarDetails,

	-- Ids
	Id, DictId,
	idName, idType, idUnique, idInfo, modifyIdInfo, maybeModifyIdInfo,
	setIdName, setIdUnique, setIdType, setIdInfo, lazySetIdInfo, 
	setIdExported, setIdNotExported, zapSpecPragmaId,

	globalIdDetails, globaliseId, 

	mkLocalId, mkExportedLocalId, mkSpecPragmaId,
	mkGlobalId, 

	isTyVar, isTcTyVar, isId, isLocalVar, isLocalId,
	isGlobalId, isExportedId, isSpecPragmaId,
	mustHaveLocalBinding
    ) where

#include "HsVersions.h"

import {-# SOURCE #-}	TypeRep( Type )
import {-# SOURCE #-}	TcType( TcTyVarDetails )
import {-# SOURCE #-}	IdInfo( GlobalIdDetails, notGlobalId, IdInfo, seqIdInfo )

import Name		( Name, OccName, NamedThing(..),
			  setNameUnique, setNameOcc, nameUnique
			)
import Kind		( Kind )
import Unique		( Unique, Uniquable(..), mkUniqueGrimily, getKey# )
import FastTypes
import Outputable
\end{code}


%************************************************************************
%*									*
\subsection{The main data type declarations}
%*									*
%************************************************************************


Every @Var@ has a @Unique@, to uniquify it and for fast comparison, a
@Type@, and an @IdInfo@ (non-essential info about it, e.g.,
strictness).  The essential info about different kinds of @Vars@ is
in its @VarDetails@.

\begin{code}
data Var
  = TyVar {
	varName    :: !Name,
	realUnique :: FastInt,		-- Key for fast comparison
					-- Identical to the Unique in the name,
					-- cached here for speed
	tyVarKind :: Kind }

  | TcTyVar { 				-- Used only during type inference
	varName        :: !Name,
	realUnique     :: FastInt,
	tyVarKind      :: Kind,
	tcTyVarDetails :: TcTyVarDetails }

  | GlobalId { 			-- Used for imported Ids, dict selectors etc
	varName    :: !Name,
	realUnique :: FastInt,
   	idType     :: Type,
	idInfo     :: IdInfo,
	gblDetails :: GlobalIdDetails }

  | LocalId { 			-- Used for locally-defined Ids (see NOTE below)
	varName    :: !Name,
	realUnique :: FastInt,
   	idType     :: Type,
	idInfo     :: IdInfo,
	lclDetails :: LocalIdDetails }

data LocalIdDetails 
  = NotExported	-- Not exported
  | Exported	-- Exported
  | SpecPragma	-- Not exported, but not to be discarded either
		-- It's unclean that this is so deeply built in
  -- Exported and SpecPragma Ids are kept alive; 
  -- NotExported things may be discarded as dead code.
\end{code}

LocalId and GlobalId
~~~~~~~~~~~~~~~~~~~~
A GlobalId is
  * always a constant (top-level)
  * imported, or data constructor, or primop, or record selector
  * has a Unique that is globally unique across the whole
    GHC invocation (a single invocation may compile multiple modules)

A LocalId is 
  * bound within an expression (lambda, case, local let(rec))
  * or defined at top level in the module being compiled

After CoreTidy, top-level LocalIds are turned into GlobalIds
 

\begin{code}
instance Outputable Var where
  ppr var = ppr (varName var)

instance Show Var where
  showsPrec p var = showsPrecSDoc p (ppr var)

instance NamedThing Var where
  getName = varName

instance Uniquable Var where
  getUnique = varUnique

instance Eq Var where
    a == b = realUnique a ==# realUnique b

instance Ord Var where
    a <= b = realUnique a <=# realUnique b
    a <	 b = realUnique a <#  realUnique b
    a >= b = realUnique a >=# realUnique b
    a >	 b = realUnique a >#  realUnique b
    a `compare` b = varUnique a `compare` varUnique b
\end{code}


\begin{code}
varUnique :: Var -> Unique
varUnique var = mkUniqueGrimily (iBox (realUnique var))

setVarUnique :: Var -> Unique -> Var
setVarUnique var uniq 
  = var { realUnique = getKey# uniq, 
	  varName = setNameUnique (varName var) uniq }

setVarName :: Var -> Name -> Var
setVarName var new_name
  = var { realUnique = getKey# (getUnique new_name), 
   	  varName = new_name }

setVarOcc :: Var -> OccName -> Var
setVarOcc var new_occ
  = var { varName = setNameOcc (varName var) new_occ }
\end{code}


%************************************************************************
%*									*
\subsection{Type variables}
%*									*
%************************************************************************

\begin{code}
type TyVar = Var

tyVarName = varName

setTyVarUnique = setVarUnique
setTyVarName   = setVarName
\end{code}

\begin{code}
mkTyVar :: Name -> Kind -> TyVar
mkTyVar name kind = TyVar { varName    = name
			  , realUnique = getKey# (nameUnique name)
			  , tyVarKind  = kind
			}

mkTcTyVar :: Name -> Kind -> TcTyVarDetails -> TyVar
mkTcTyVar name kind details
  = TcTyVar {	varName    = name,
		realUnique = getKey# (nameUnique name),
		tyVarKind  = kind,
		tcTyVarDetails = details
	}
\end{code}


%************************************************************************
%*									*
\subsection{Id Construction}
%*									*
%************************************************************************

Most Id-related functions are in Id.lhs and MkId.lhs

\begin{code}
type Id     = Var
type DictId = Id
\end{code}

\begin{code}
idName    = varName
idUnique  = varUnique

setIdUnique :: Id -> Unique -> Id
setIdUnique = setVarUnique

setIdName :: Id -> Name -> Id
setIdName = setVarName

setIdType :: Id -> Type -> Id
setIdType id ty = id {idType = ty}

setIdExported :: Id -> Id
-- Can be called on GlobalIds, such as data cons and class ops,
-- which are "born" as GlobalIds and automatically exported
setIdExported id@(LocalId {}) = id { lclDetails = Exported }
setIdExported other_id	      = ASSERT( isId other_id ) other_id

setIdNotExported :: Id -> Id
-- We can only do this to LocalIds
setIdNotExported id = ASSERT( isLocalId id ) id { lclDetails = NotExported }

zapSpecPragmaId :: Id -> Id
zapSpecPragmaId id
  | isSpecPragmaId id = id {lclDetails = NotExported}
  | otherwise         = id

globaliseId :: GlobalIdDetails -> Id -> Id
-- If it's a local, make it global
globaliseId details id = GlobalId { varName    = varName id,
				    realUnique = realUnique id,
			   	    idType     = idType id,
				    idInfo     = idInfo id,
				    gblDetails = details }

lazySetIdInfo :: Id -> IdInfo -> Id
lazySetIdInfo id info = id {idInfo = info}

setIdInfo :: Id -> IdInfo -> Id
setIdInfo id info = seqIdInfo info `seq` id {idInfo = info}
	-- Try to avoid spack leaks by seq'ing

modifyIdInfo :: (IdInfo -> IdInfo) -> Id -> Id
modifyIdInfo fn id
  = seqIdInfo new_info `seq` id {idInfo = new_info}
  where
    new_info = fn (idInfo id)

-- maybeModifyIdInfo tries to avoid unnecesary thrashing
maybeModifyIdInfo :: (IdInfo -> Maybe IdInfo) -> Id -> Id
maybeModifyIdInfo fn id
  = case fn (idInfo id) of
	Nothing       -> id
	Just new_info -> id {idInfo = new_info}
\end{code}

%************************************************************************
%*									*
\subsection{Predicates over variables
%*									*
%************************************************************************

\begin{code}
mkGlobalId :: GlobalIdDetails -> Name -> Type -> IdInfo -> Id
mkGlobalId details name ty info 
  = GlobalId {	varName    = name, 
		realUnique = getKey# (nameUnique name), 	-- Cache the unique
		idType     = ty,	
		gblDetails = details,
		idInfo     = info }

mk_local_id :: Name -> Type -> LocalIdDetails -> IdInfo -> Id
mk_local_id name ty details info
  = LocalId {	varName    = name, 
		realUnique = getKey# (nameUnique name), 	-- Cache the unique
		idType     = ty,	
		lclDetails = details,
		idInfo     = info }

mkLocalId :: Name -> Type -> IdInfo -> Id
mkLocalId name ty info = mk_local_id name ty NotExported info

mkExportedLocalId :: Name -> Type -> IdInfo -> Id
mkExportedLocalId name ty info = mk_local_id name ty Exported info

mkSpecPragmaId :: Name -> Type -> IdInfo -> Id
mkSpecPragmaId name ty info = mk_local_id name ty SpecPragma info
\end{code}

\begin{code}
isTyVar, isTcTyVar			 :: Var -> Bool
isId, isLocalVar, isLocalId    		 :: Var -> Bool
isGlobalId, isExportedId, isSpecPragmaId :: Var -> Bool
mustHaveLocalBinding			 :: Var -> Bool

isTyVar (TyVar {})   = True
isTyVar (TcTyVar {}) = True
isTyVar other	     = False

isTcTyVar (TcTyVar {}) = True
isTcTyVar other	       = False

isId (LocalId {})  = True
isId (GlobalId {}) = True
isId other	   = False

isLocalId (LocalId {}) = True
isLocalId other	       = False

-- isLocalVar returns True for type variables as well as local Ids
-- These are the variables that we need to pay attention to when finding free
-- variables, or doing dependency analysis.
isLocalVar (GlobalId {}) = False 
isLocalVar other	 = True

-- mustHaveLocalBinding returns True of Ids and TyVars
-- that must have a binding in this module.  The converse
-- is not quite right: there are some GlobalIds that must have
-- bindings, such as record selectors.  But that doesn't matter,
-- because it's only used for assertions
mustHaveLocalBinding var = isLocalVar var

isGlobalId (GlobalId {}) = True
isGlobalId other	 = False

-- isExportedId means "don't throw this away"
isExportedId (GlobalId {}) = True
isExportedId (LocalId {lclDetails = details}) 
  = case details of
	Exported   -> True
	SpecPragma -> True
	other	   -> False
isExportedId other = False

isSpecPragmaId (LocalId {lclDetails = SpecPragma}) = True
isSpecPragmaId other = False
\end{code}

\begin{code}
globalIdDetails :: Var -> GlobalIdDetails
-- Works OK on local Ids too, returning notGlobalId
globalIdDetails (GlobalId {gblDetails = details}) = details
globalIdDetails other				  = notGlobalId
\end{code}

