\section[HscTypes]{Types for the per-module compiler}
\begin{code}
-module HscTypes ( )
-where
+module HscTypes (
+ ModuleLocation(..),
+
+ ModDetails(..), ModIface(..),
+ HomeSymbolTable, PackageTypeEnv,
+ HomeIfaceTable, PackageIfaceTable, emptyIfaceTable,
+ lookupTable, lookupTableByModName,
+ emptyModIface,
+
+ IfaceDecls(..),
+
+ VersionInfo(..), initialVersionInfo,
+
+ TyThing(..), isTyClThing,
+
+ TypeEnv, lookupType, mkTypeEnv, extendTypeEnvList,
+ typeEnvClasses, typeEnvTyCons,
+
+ WhetherHasOrphans, ImportVersion, WhatsImported(..),
+ PersistentRenamerState(..), IsBootInterface, Avails, DeclsMap,
+ IfaceInsts, IfaceRules, GatedDecl,
+ OrigNameEnv(..), OrigNameNameEnv, OrigNameIParamEnv,
+ AvailEnv, AvailInfo, GenAvailInfo(..),
+ PersistentCompilerState(..),
+
+ Deprecations(..), lookupDeprec,
+
+ InstEnv, ClsInstEnv, DFunId,
+ PackageInstEnv, PackageRuleBase,
+
+ GlobalRdrEnv, RdrAvailInfo,
+
+ -- Provenance
+ Provenance(..), ImportReason(..), PrintUnqualified,
+ pprNameProvenance, hasBetterProv
+
+ ) where
#include "HsVersions.h"
+import RdrName ( RdrNameEnv, emptyRdrEnv )
+import Name ( Name, NameEnv, NamedThing,
+ emptyNameEnv, extendNameEnv,
+ lookupNameEnv, emptyNameEnv, getName, nameModule,
+ nameSrcLoc, nameEnvElts )
+import NameSet ( NameSet )
+import OccName ( OccName )
+import Module ( Module, ModuleName, ModuleEnv,
+ lookupModuleEnv, lookupModuleEnvByName
+ )
+import Rules ( RuleBase )
+import VarSet ( TyVarSet )
+import Id ( Id )
+import Class ( Class )
+import TyCon ( TyCon )
+
+import BasicTypes ( Version, initialVersion, Fixity )
+
+import HsSyn ( DeprecTxt )
+import RdrHsSyn ( RdrNameHsDecl, RdrNameTyClDecl )
+import RnHsSyn ( RenamedTyClDecl, RenamedRuleDecl, RenamedInstDecl )
+
+import CoreSyn ( IdCoreRule )
+import Type ( Type )
+
+import FiniteMap ( FiniteMap )
+import Bag ( Bag )
+import Maybes ( seqMaybe )
+import UniqFM ( UniqFM, emptyUFM )
+import Outputable
+import SrcLoc ( SrcLoc, isGoodSrcLoc )
+import Util ( thenCmp )
+import UniqSupply ( UniqSupply )
\end{code}
%************************************************************************
%* *
+\subsection{Module locations}
+%* *
+%************************************************************************
+
+\begin{code}
+data ModuleLocation
+ = ModuleLocation {
+ hs_preprocd_file :: FilePath, -- location after preprocessing
+ hi_file :: FilePath,
+ obj_file :: FilePath
+ }
+ deriving Show
+
+instance Outputable ModuleLocation where
+ ppr = text . show
+\end{code}
+
+For a module in another package, the hs_file and obj_file
+components of ModuleLocation are undefined.
+
+The locations specified by a ModuleLocation may or may not
+correspond to actual files yet: for example, even if the object
+file doesn't exist, the ModuleLocation still contains the path to
+where the object file will reside if/when it is created.
+
+
+%************************************************************************
+%* *
\subsection{Symbol tables and Module details}
%* *
%************************************************************************
-A @ModDetails@ summarises everything we know about a compiled module
+A @ModIface@ plus a @ModDetails@ summarises everything we know
+about a compiled module. The @ModIface@ is the stuff *before* linking,
+and can be written out to an interface file. The @ModDetails@ is after
+linking; it is the "linked" form of the mi_decls field.
\begin{code}
+data ModIface
+ = ModIface {
+ mi_module :: Module, -- Complete with package info
+ mi_version :: VersionInfo, -- Module version number
+ mi_orphan :: WhetherHasOrphans, -- Whether this module has orphans
+ mi_boot :: IsBootInterface, -- Whether this interface was read from an hi-boot file
+
+ mi_usages :: [ImportVersion Name], -- Usages; kept sorted so that it's easy
+ -- to decide whether to write a new iface file
+ -- (changing usages doesn't affect the version of
+ -- this module)
+
+ mi_exports :: [(ModuleName,Avails)], -- What it exports
+ -- Kept sorted by (mod,occ),
+ -- to make version comparisons easier
+
+ mi_globals :: GlobalRdrEnv, -- Its top level environment
+
+ mi_fixities :: NameEnv Fixity, -- Fixities
+ mi_deprecs :: Deprecations, -- Deprecations
+
+ mi_decls :: IfaceDecls -- The RnDecls form of ModDetails
+ }
+
+data IfaceDecls = IfaceDecls { dcl_tycl :: [RenamedTyClDecl], -- Sorted
+ dcl_rules :: [RenamedRuleDecl], -- Sorted
+ dcl_insts :: [RenamedInstDecl] } -- Unsorted
+
+-- typechecker should only look at this, not ModIface
+-- Should be able to construct ModDetails from mi_decls in ModIface
data ModDetails
= ModDetails {
- moduleExports :: Avails, -- What it exports
- moduleEnv :: GlobalRdrEnv, -- Its top level environment
+ -- The next three fields are created by the typechecker
+ md_types :: TypeEnv,
+ md_insts :: [DFunId], -- Dfun-ids for the instances in this module
+ md_rules :: [IdCoreRule] -- Domain may include Ids from other modules
+ }
+\end{code}
- fixityEnv :: NameEnv Fixity,
- deprecEnv :: NameEnv DeprecTxt,
- typeEnv :: NameEnv TyThing, -- TyThing is in TcEnv.lhs
+\begin{code}
+emptyModDetails :: ModDetails
+emptyModDetails
+ = ModDetails { md_types = emptyTypeEnv,
+ md_insts = [],
+ md_rules = []
+ }
- instEnv :: InstEnv,
- ruleEnv :: IdEnv [CoreRule] -- Domain includes Ids from other modules
- }
+emptyModIface :: Module -> ModIface
+emptyModIface mod
+ = ModIface { mi_module = mod,
+ mi_version = initialVersionInfo,
+ mi_usages = [],
+ mi_orphan = False,
+ mi_boot = False,
+ mi_exports = [],
+ mi_fixities = emptyNameEnv,
+ mi_globals = emptyRdrEnv,
+ mi_deprecs = NoDeprecs,
+ mi_decls = panic "emptyModIface: decls"
+ }
\end{code}
Symbol tables map modules to ModDetails:
\begin{code}
-type HomeSymbolTable = ModuleEnv ModDetails -- Domain = modules in the home package
-type PackageSymbolTable = ModuleEnv ModDetails -- Domain = modules in the some other package
-type GlobalSymbolTable = ModuleEnv ModDetails -- Domain = all modules
+type SymbolTable = ModuleEnv ModDetails
+type IfaceTable = ModuleEnv ModIface
+
+type HomeIfaceTable = IfaceTable
+type PackageIfaceTable = IfaceTable
+
+type HomeSymbolTable = SymbolTable -- Domain = modules in the home package
+
+emptyIfaceTable :: IfaceTable
+emptyIfaceTable = emptyUFM
\end{code}
+Simple lookups in the symbol table.
-Auxiliary definitions
+\begin{code}
+lookupTable :: ModuleEnv a -> ModuleEnv a -> Name -> Maybe a
+-- We often have two Symbol- or IfaceTables, and want to do a lookup
+lookupTable ht pt name
+ = lookupModuleEnv ht mod `seqMaybe` lookupModuleEnv pt mod
+ where
+ mod = nameModule name
+
+lookupTableByModName :: ModuleEnv a -> ModuleEnv a -> ModuleName -> Maybe a
+-- We often have two Symbol- or IfaceTables, and want to do a lookup
+lookupTableByModName ht pt mod
+ = lookupModuleEnvByName ht mod `seqMaybe` lookupModuleEnvByName pt mod
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Type environment stuff}
+%* *
+%************************************************************************
\begin{code}
data TyThing = AnId Id
| ATyCon TyCon
| AClass Class
-type DeprecationEnv = NameEnv DeprecTxt -- Give reason for deprecation
+isTyClThing :: TyThing -> Bool
+isTyClThing (ATyCon _) = True
+isTyClThing (AClass _) = True
+isTyClThing (AnId _) = False
+
+instance NamedThing TyThing where
+ getName (AnId id) = getName id
+ getName (ATyCon tc) = getName tc
+ getName (AClass cl) = getName cl
+
+typeEnvClasses env = [cl | AClass cl <- nameEnvElts env]
+typeEnvTyCons env = [tc | ATyCon tc <- nameEnvElts env]
+
+\end{code}
+
+
+\begin{code}
+type TypeEnv = NameEnv TyThing
+
+emptyTypeEnv = emptyNameEnv
+
+mkTypeEnv :: [TyThing] -> TypeEnv
+mkTypeEnv things = extendTypeEnvList emptyTypeEnv things
+
+extendTypeEnvList :: TypeEnv -> [TyThing] -> TypeEnv
+extendTypeEnvList env things
+ = foldl add_thing env things
+ where
+ add_thing :: TypeEnv -> TyThing -> TypeEnv
+ add_thing env thing = extendNameEnv env (getName thing) thing
+\end{code}
+
+\begin{code}
+lookupType :: HomeSymbolTable -> PackageTypeEnv -> Name -> Maybe TyThing
+lookupType hst pte name
+ = case lookupModuleEnv hst (nameModule name) of
+ Just details -> lookupNameEnv (md_types details) name
+ Nothing -> lookupNameEnv pte name
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Auxiliary types}
+%* *
+%************************************************************************
-type GlobalRdrEnv = RdrNameEnv [Name] -- The list is because there may be name clashes
- -- These only get reported on lookup,
- -- not on construction
+These types are defined here because they are mentioned in ModDetails,
+but they are mostly elaborated elsewhere
+
+\begin{code}
+data VersionInfo
+ = VersionInfo {
+ vers_module :: Version, -- Changes when anything changes
+ vers_exports :: Version, -- Changes when export list changes
+ vers_rules :: Version, -- Changes when any rule changes
+ vers_decls :: NameEnv Version
+ -- Versions for "big" names only (not data constructors, class ops)
+ -- The version of an Id changes if its fixity changes
+ -- Ditto data constructors, class operations, except that the version of
+ -- the parent class/tycon changes
+ }
+
+initialVersionInfo :: VersionInfo
+initialVersionInfo = VersionInfo { vers_module = initialVersion,
+ vers_exports = initialVersion,
+ vers_rules = initialVersion,
+ vers_decls = emptyNameEnv }
+
+data Deprecations = NoDeprecs
+ | DeprecAll DeprecTxt -- Whole module deprecated
+ | DeprecSome (NameEnv (Name,DeprecTxt)) -- Some things deprecated
+ -- Just "big" names
+ -- We keep the Name in the range, so we can print them out
+
+lookupDeprec :: Deprecations -> Name -> Maybe DeprecTxt
+lookupDeprec NoDeprecs name = Nothing
+lookupDeprec (DeprecAll txt) name = Just txt
+lookupDeprec (DeprecSome env) name = case lookupNameEnv env name of
+ Just (_, txt) -> Just txt
+ Nothing -> Nothing
+
+type InstEnv = UniqFM ClsInstEnv -- Maps Class to instances for that class
+
+type ClsInstEnv = [(TyVarSet, [Type], DFunId)] -- The instances for a particular class
+type DFunId = Id
+\end{code}
+
+
+\begin{code}
+type Avails = [AvailInfo]
+type AvailInfo = GenAvailInfo Name
+type RdrAvailInfo = GenAvailInfo OccName
data GenAvailInfo name = Avail name -- An ordinary identifier
| AvailTC name -- The name of the type or class
-- Equality used when deciding if the interface has changed
type AvailEnv = NameEnv AvailInfo -- Maps a Name to the AvailInfo that contains it
-type AvailInfo = GenAvailInfo Name
-type RdrAvailInfo = GenAvailInfo OccName
-type Avails = [AvailInfo]
\end{code}
%************************************************************************
\begin{code}
--- ModIFace is nearly the same as RnMonad.ParsedIface.
--- Right now it's identical :)
-data ModIFace
- = ModIFace {
- mi_mod :: Module, -- Complete with package info
- mi_vers :: Version, -- Module version number
- mi_orphan :: WhetherHasOrphans, -- Whether this module has orphans
- mi_usages :: [ImportVersion OccName], -- Usages
- mi_exports :: [ExportItem], -- Exports
- mi_insts :: [RdrNameInstDecl], -- Local instance declarations
- mi_decls :: [(Version, RdrNameHsDecl)], -- Local definitions
- mi_fixity :: (Version, [RdrNameFixitySig]), -- Local fixity declarations,
- -- with their version
- mi_rules :: (Version, [RdrNameRuleDecl]), -- Rules, with their version
- mi_deprecs :: [RdrNameDeprecation] -- Deprecations
- }
+type WhetherHasOrphans = Bool
+ -- An "orphan" is
+ -- * an instance decl in a module other than the defn module for
+ -- one of the tycons or classes in the instance head
+ -- * a transformation rule in a module other than the one defining
+ -- the function in the head of the rule.
+
+type IsBootInterface = Bool
+
+type ImportVersion name = (ModuleName, WhetherHasOrphans, IsBootInterface, WhatsImported name)
+
+data WhatsImported name = NothingAtAll -- The module is below us in the
+ -- hierarchy, but we import nothing
+
+ | Everything Version -- Used for modules from other packages;
+ -- we record only the module's version number
+
+ | Specifically
+ Version -- Module version
+ (Maybe Version) -- Export-list version, if we depend on it
+ [(name,Version)] -- List guaranteed non-empty
+ Version -- Rules version
+
+ deriving( Eq )
+ -- 'Specifically' doesn't let you say "I imported f but none of the rules in
+ -- the module". If you use anything in the module you get its rule version
+ -- So if the rules change, you'll recompile, even if you don't use them.
+ -- This is easy to implement, and it's safer: you might not have used the rules last
+ -- time round, but if someone has added a new rule you might need it this time
+
+ -- The export list field is (Just v) if we depend on the export list:
+ -- we imported the module without saying exactly what we imported
+ -- We need to recompile if the module exports changes, because we might
+ -- now have a name clash in the importing module.
\end{code}
\begin{code}
data PersistentCompilerState
= PCS {
- pcsPST :: PackageSymbolTable, -- Domain = non-home-package modules
- pcsPRS :: PersistentRenamerState
+ pcs_PIT :: PackageIfaceTable, -- Domain = non-home-package modules
+ -- the mi_decls component is empty
+
+ pcs_PTE :: PackageTypeEnv, -- Domain = non-home-package modules
+ -- except that the InstEnv components is empty
+
+ pcs_insts :: PackageInstEnv, -- The total InstEnv accumulated from all
+ -- the non-home-package modules
+
+ pcs_rules :: PackageRuleBase, -- Ditto RuleEnv
+
+ pcs_PRS :: PersistentRenamerState
}
+
\end{code}
The @PersistentRenamerState@ persists across successive calls to the
compiler.
It contains:
- * a name supply, which deals with allocating unique names to
+ * A name supply, which deals with allocating unique names to
(Module,OccName) original names,
- * a "holding pen" for declarations that have been read out of
+ * An accumulated TypeEnv from all the modules in imported packages
+
+ * An accumulated InstEnv from all the modules in imported packages
+ The point is that we don't want to keep recreating it whenever
+ we compile a new module. The InstEnv component of pcPST is empty.
+ (This means we might "see" instances that we shouldn't "really" see;
+ but the Haskell Report is vague on what is meant to be visible,
+ so we just take the easy road here.)
+
+ * Ditto for rules
+
+ * A "holding pen" for declarations that have been read out of
interface files but not yet sucked in, renamed, and typechecked
\begin{code}
+type PackageTypeEnv = TypeEnv
+type PackageRuleBase = RuleBase
+type PackageInstEnv = InstEnv
+
data PersistentRenamerState
- = PRS { prsNS :: NameSupply,
+ = PRS { prsOrig :: OrigNameEnv,
prsDecls :: DeclsMap,
prsInsts :: IfaceInsts,
prsRules :: IfaceRules,
+ prsNS :: UniqSupply
}
+\end{code}
+
+The OrigNameEnv makes sure that there is just one Unique assigned for
+each original name; i.e. (module-name, occ-name) pair. The Name is
+always stored as a Global, and has the SrcLoc of its binding location.
+Actually that's not quite right. When we first encounter the original
+name, we might not be at its binding site (e.g. we are reading an
+interface file); so we give it 'noSrcLoc' then. Later, when we find
+its binding site, we fix it up.
-data NameSupply
- = NS { nsUniqs :: UniqSupply,
- nsNames :: FiniteMap (Module,OccName) Name -- Ensures that one original name gets one unique
- nsIParam :: FiniteMap OccName Name -- Ensures that one implicit parameter name gets one unique
+Exactly the same is true of the Module stored in the Name. When we first
+encounter the occurrence, we may not know the details of the module, so
+we just store junk. Then when we find the binding site, we fix it up.
+
+\begin{code}
+data OrigNameEnv
+ = Orig { origNames :: OrigNameNameEnv,
+ -- Ensures that one original name gets one unique
+ origIParam :: OrigNameIParamEnv
+ -- Ensures that one implicit parameter name gets one unique
}
-type DeclsMap = NameEnv (Version, AvailInfo, Bool, (Module, RdrNameHsDecl))
- -- A DeclsMap contains a binding for each Name in the declaration
- -- including the constructors of a type decl etc.
- -- The Bool is True just for the 'main' Name.
+type OrigNameNameEnv = FiniteMap (ModuleName,OccName) Name
+type OrigNameIParamEnv = FiniteMap OccName Name
+\end{code}
+
+
+A DeclsMap contains a binding for each Name in the declaration
+including the constructors of a type decl etc. The Bool is True just
+for the 'main' Name.
+
+\begin{code}
+type DeclsMap = NameEnv (AvailInfo, Bool, (Module, RdrNameTyClDecl))
type IfaceInsts = Bag GatedDecl
type IfaceRules = Bag GatedDecl
%************************************************************************
%* *
-\subsection{The result of compiling one module}
+\subsection{Provenance and export info}
%* *
%************************************************************************
-\begin{code}
-data CompResult
- = CompOK ModDetails -- new details (HST additions)
- (Maybe (ModIFace, Linkable))
- -- summary and code; Nothing => compilation not reqd
- -- (old summary and code are still valid)
- PersistentCompilerState -- updated PCS
- (Bag WarnMsg) -- warnings
-
- | CompErrs PersistentCompilerState -- updated PCS
- (Bag ErrMsg) -- errors
- (Bag WarnMsg) -- warnings
-
-
--- The driver sits between 'compile' and 'hscMain', translating calls
--- to the former into calls to the latter, and results from the latter
--- into results from the former. It does things like preprocessing
--- the .hs file if necessary, and compiling up the .stub_c files to
--- generate Linkables.
-
-data HscResult
- = HscOK ModDetails -- new details (HomeSymbolTable additions)
- Maybe ModIFace -- new iface (if any compilation was done)
- Maybe String -- generated stub_h
- Maybe String -- generated stub_c
- PersistentCompilerState -- updated PCS
- [SDoc] -- warnings
+The GlobalRdrEnv gives maps RdrNames to Names. There is a separate
+one for each module, corresponding to that module's top-level scope.
- | HscErrs PersistentCompilerState -- updated PCS
- [SDoc] -- errors
- [SDoc] -- warnings
+\begin{code}
+type GlobalRdrEnv = RdrNameEnv [(Name,Provenance)] -- The list is because there may be name clashes
+ -- These only get reported on lookup,
+ -- not on construction
+\end{code}
-
--- These two are only here to avoid recursion between CmCompile and
--- CompManager. They really ought to be in the latter.
-type ModuleEnv a = UniqFM a -- Domain is Module
+The "provenance" of something says how it came to be in scope.
-type HomeModMap = FiniteMap ModuleName Module -- domain: home mods only
-type HomeInterfaceTable = ModuleEnv ModIFace
+\begin{code}
+data Provenance
+ = LocalDef -- Defined locally
+
+ | NonLocalDef -- Defined non-locally
+ ImportReason
+ PrintUnqualified
+
+-- Just used for grouping error messages (in RnEnv.warnUnusedBinds)
+instance Eq Provenance where
+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False
+
+instance Eq ImportReason where
+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False
+
+instance Ord Provenance where
+ compare LocalDef LocalDef = EQ
+ compare LocalDef (NonLocalDef _ _) = LT
+ compare (NonLocalDef _ _) LocalDef = GT
+
+ compare (NonLocalDef reason1 _) (NonLocalDef reason2 _)
+ = compare reason1 reason2
+
+instance Ord ImportReason where
+ compare ImplicitImport ImplicitImport = EQ
+ compare ImplicitImport (UserImport _ _ _) = LT
+ compare (UserImport _ _ _) ImplicitImport = GT
+ compare (UserImport m1 loc1 _) (UserImport m2 loc2 _)
+ = (m1 `compare` m2) `thenCmp` (loc1 `compare` loc2)
+
+
+data ImportReason
+ = UserImport Module SrcLoc Bool -- Imported from module M on line L
+ -- Note the M may well not be the defining module
+ -- for this thing!
+ -- The Bool is true iff the thing was named *explicitly* in the import spec,
+ -- rather than being imported as part of a group; e.g.
+ -- import B
+ -- import C( T(..) )
+ -- Here, everything imported by B, and the constructors of T
+ -- are not named explicitly; only T is named explicitly.
+ -- This info is used when warning of unused names.
+
+ | ImplicitImport -- Imported implicitly for some other reason
+
+
+type PrintUnqualified = Bool -- True <=> the unqualified name of this thing is
+ -- in scope in this module, so print it
+ -- unqualified in error messages
\end{code}
-
+\begin{code}
+hasBetterProv :: Provenance -> Provenance -> Bool
+-- Choose
+-- a local thing over an imported thing
+-- a user-imported thing over a non-user-imported thing
+-- an explicitly-imported thing over an implicitly imported thing
+hasBetterProv LocalDef _ = True
+hasBetterProv (NonLocalDef (UserImport _ _ True) _) _ = True
+hasBetterProv (NonLocalDef (UserImport _ _ _ ) _) (NonLocalDef ImplicitImport _) = True
+hasBetterProv _ _ = False
+
+pprNameProvenance :: Name -> Provenance -> SDoc
+pprNameProvenance name LocalDef = ptext SLIT("defined at") <+> ppr (nameSrcLoc name)
+pprNameProvenance name (NonLocalDef why _) = sep [ppr_reason why,
+ nest 2 (parens (ppr_defn (nameSrcLoc name)))]
+
+ppr_reason ImplicitImport = ptext SLIT("implicitly imported")
+ppr_reason (UserImport mod loc _) = ptext SLIT("imported from") <+> ppr mod <+> ptext SLIT("at") <+> ppr loc
+
+ppr_defn loc | isGoodSrcLoc loc = ptext SLIT("at") <+> ppr loc
+ | otherwise = empty
+\end{code}