%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
\section[RnIfaces]{Cacheing and Renaming of Interfaces}
\begin{code}
-#include "HsVersions.h"
+module RnIfaces
+ (
+ getInterfaceExports,
+ recordLocalSlurps,
+ mkImportInfo,
-module RnIfaces (
- cachedIface,
- cachedDecl, CachingResult(..),
- rnIfaces,
- IfaceCache, initIfaceCache
- ) where
-
-IMP_Ubiq()
-
-import PreludeGlaST ( thenPrimIO, newVar, readVar, writeVar, SYN_IE(MutableVar) )
-#if __GLASGOW_HASKELL__ >= 200
-# define ST_THEN `stThen`
-# define TRY_IO tryIO
-IMPORT_1_3(GHCio(stThen,tryIO))
-#else
-# define ST_THEN `thenPrimIO`
-# define TRY_IO try
-#endif
+ slurpImpDecls, closeDecls,
-import HsSyn
-import HsPragmas ( noGenPragmas )
-import RdrHsSyn
-import RnHsSyn
+ RecompileRequired, outOfDate, upToDate, recompileRequired
+ )
+where
-import RnMonad
-import RnSource ( rnTyDecl, rnClassDecl, rnInstDecl, rnPolyType )
-import RnUtils ( SYN_IE(RnEnv), emptyRnEnv, lookupRnEnv, lookupTcRnEnv, extendGlobalRnEnv )
-import ParseIface ( parseIface )
-import ParseUtils ( ParsedIface(..), RdrIfaceDecl(..), RdrIfaceInst(..),
- VersionsMap(..), UsagesMap(..)
- )
+#include "HsVersions.h"
-import Bag ( emptyBag, unitBag, consBag, snocBag,
- unionBags, unionManyBags, isEmptyBag, bagToList )
-import ErrUtils ( SYN_IE(Error), SYN_IE(Warning) )
-import FiniteMap ( emptyFM, lookupFM, addToFM, addToFM_C, plusFM, eltsFM,
- fmToList, delListFromFM, sizeFM, foldFM, unitFM,
- plusFM_C, addListToFM{-, keysFM ToDo:rm-}, FiniteMap
+import CmdLineOpts ( opt_IgnoreIfacePragmas, opt_NoPruneDecls )
+import HscTypes
+import HsSyn ( HsDecl(..), Sig(..), TyClDecl(..), ConDecl(..), ConDetails(..),
+ InstDecl(..), HsType(..), hsTyVarNames, getBangType
+ )
+import HsImpExp ( ImportDecl(..) )
+import RdrHsSyn ( RdrNameTyClDecl, RdrNameInstDecl, RdrNameRuleDecl )
+import RnHsSyn ( RenamedHsDecl, RenamedTyClDecl,
+ extractHsTyNames, extractHsCtxtTyNames,
+ tyClDeclFVs, ruleDeclFVs, instDeclFVs
+ )
+import RnHiFiles ( tryLoadInterface, loadHomeInterface, loadInterface,
+ loadOrphanModules
)
-import Maybes ( maybeToBool, MaybeErr(..) )
-import Name ( origName, moduleOf, nameOf, qualToOrigName, OrigName(..),
- isLexCon, RdrName(..), Name{-instance NamedThing-} )
---import PprStyle -- ToDo:rm
---import Outputable -- ToDo:rm
-import PrelInfo ( builtinNameMaps, builtinKeysMap, builtinTcNamesMap, SYN_IE(BuiltinNames) )
-import Pretty
-import UniqFM ( emptyUFM )
-import UniqSupply ( splitUniqSupply )
-import Util ( sortLt, removeDups, cmpPString, startsWith,
- panic, pprPanic, assertPanic{-, pprTrace ToDo:rm-} )
+import RnSource ( rnTyClDecl, rnInstDecl, rnIfaceRuleDecl )
+import RnEnv
+import RnMonad
+import Id ( idType )
+import Type ( namesOfType )
+import TyCon ( isSynTyCon, getSynTyConDefn )
+import Name ( Name {-instance NamedThing-}, nameOccName,
+ nameModule, isLocalName, nameUnique,
+ NamedThing(..)
+ )
+import Name ( elemNameEnv, delFromNameEnv )
+import Module ( Module, ModuleEnv,
+ moduleName, isHomeModule,
+ ModuleName, WhereFrom(..),
+ emptyModuleEnv,
+ extendModuleEnv_C, foldModuleEnv, lookupModuleEnv,
+ elemModuleSet, extendModuleSet
+ )
+import NameSet
+import PrelInfo ( wiredInThingEnv, fractionalClassKeys )
+import TysWiredIn ( doubleTyCon )
+import Maybes ( orElse )
+import FiniteMap
+import Outputable
+import Bag
+import Util ( sortLt )
\end{code}
-\begin{code}
-type ModuleToIfaceContents = FiniteMap Module ParsedIface
-type ModuleToIfaceFilePath = FiniteMap Module FilePath
-#if __GLASGOW_HASKELL__ >= 200
-# define REAL_WORLD RealWorld
-#else
-# define REAL_WORLD _RealWorld
-#endif
+%*********************************************************
+%* *
+\subsection{Getting what a module exports}
+%* *
+%*********************************************************
+
+@getInterfaceExports@ is called only for directly-imported modules.
-data IfaceCache
- = IfaceCache
- Module -- the name of the module being compiled
- BuiltinNames -- so we can avoid going after things
- -- the compiler already knows about
- (MutableVar REAL_WORLD
- (ModuleToIfaceContents, -- interfaces for individual interface files
- ModuleToIfaceContents, -- merged interfaces based on module name
- -- used for extracting info about original names
- ModuleToIfaceFilePath))
-
-initIfaceCache mod hi_files
- = newVar (emptyFM,emptyFM,hi_files) ST_THEN \ iface_var ->
- return (IfaceCache mod builtinNameMaps iface_var)
+\begin{code}
+getInterfaceExports :: ModuleName -> WhereFrom -> RnMG (Module, [(ModuleName,Avails)])
+getInterfaceExports mod_name from
+ = loadInterface doc_str mod_name from `thenRn` \ iface ->
+ returnRn (mi_module iface, mi_exports iface)
+ where
+ doc_str = sep [ppr mod_name, ptext SLIT("is directly imported")]
\end{code}
-*********************************************************
-* *
-\subsection{Reading interface files}
-* *
-*********************************************************
-Return cached info about a Module's interface; otherwise,
-read the interface (using our @ModuleToIfaceFilePath@ map
-to decide where to look).
+%*********************************************************
+%* *
+\subsection{Keeping track of what we've slurped, and version numbers}
+%* *
+%*********************************************************
-Note: we have two notions of interface
- * the interface for a particular file name
- * the (combined) interface for a particular module name
+mkImportInof figures out what the ``usage information'' for this
+moudule is; that is, what it must record in its interface file as the
+things it uses.
-The idea is that two source files may declare a module
-with the same name with the declarations being merged.
+We produce a line for every module B below the module, A, currently being
+compiled:
+ import B <n> ;
+to record the fact that A does import B indireclty. This is used to decide
+to look to look for B.hi rather than B.hi-boot when compiling a module that
+imports A. This line says that A imports B, but uses nothing in it.
+So we'll get an early bale-out when compiling A if B's version changes.
-This allows us to have file PreludeList.hs producing
-PreludeList.hi but defining part of module Prelude.
-When PreludeList is imported its contents will be
-added to Prelude. In this way all the original names
-for a particular module will be available the imported
-decls are renamed.
+\begin{code}
+mkImportInfo :: ModuleName -- Name of this module
+ -> [ImportDecl n] -- The import decls
+ -> RnMG [ImportVersion Name]
-ToDo: Check duplicate definitons are the same.
-ToDo: Check/Merge duplicate pragmas.
+mkImportInfo this_mod imports
+ = getIfacesRn `thenRn` \ ifaces ->
+ getHomeIfaceTableRn `thenRn` \ hit ->
+ let
+ (imp_pkg_mods, imp_home_names) = iVSlurp ifaces
+ pit = iPIT ifaces
+
+ import_all_mods :: [ModuleName]
+ -- Modules where we imported all the names
+ -- (apart from hiding some, perhaps)
+ import_all_mods = [ m | ImportDecl m _ _ _ imp_list _ <- imports,
+ import_all imp_list ]
+ where
+ import_all (Just (False, _)) = False -- Imports are specified explicitly
+ import_all other = True -- Everything is imported
+
+ -- mv_map groups together all the things imported and used
+ -- from a particular module in this package
+ -- We use a finite map because we want the domain
+ mv_map :: ModuleEnv [Name]
+ mv_map = foldNameSet add_mv emptyModuleEnv imp_home_names
+ add_mv name mv_map = extendModuleEnv_C add_item mv_map mod [name]
+ where
+ mod = nameModule name
+ add_item names _ = name:names
+
+ -- In our usage list we record
+ -- a) Specifically: Detailed version info for imports from modules in this package
+ -- Gotten from iVSlurp plus import_all_mods
+ --
+ -- b) Everything: Just the module version for imports from modules in other packages
+ -- Gotten from iVSlurp plus import_all_mods
+ --
+ -- c) NothingAtAll: The name only of modules, Baz, in this package that are 'below' us,
+ -- but which we didn't need at all (this is needed only to decide whether
+ -- to open Baz.hi or Baz.hi-boot higher up the tree).
+ -- This happens when a module, Foo, that we explicitly imported has
+ -- 'import Baz' in its interface file, recording that Baz is below
+ -- Foo in the module dependency hierarchy. We want to propagate this info.
+ -- These modules are in a combination of HIT/PIT and iImpModInfo
+ --
+ -- d) NothingAtAll: The name only of all orphan modules we know of (this is needed
+ -- so that anyone who imports us can find the orphan modules)
+ -- These modules are in a combination of HIT/PIT and iImpModInfo
+
+ import_info0 = foldModuleEnv mk_imp_info [] pit
+ import_info1 = foldModuleEnv mk_imp_info import_info0 hit
+ import_info = [ (mod_name, orphans, is_boot, NothingAtAll)
+ | (mod_name, (orphans, is_boot)) <- fmToList (iImpModInfo ifaces) ] ++
+ import_info1
+
+ mk_imp_info :: ModIface -> [ImportVersion Name] -> [ImportVersion Name]
+ mk_imp_info iface so_far
+
+ | Just ns <- lookupModuleEnv mv_map mod -- Case (a)
+ = go_for_it (Specifically mod_vers maybe_export_vers
+ (mk_import_items ns) rules_vers)
+
+ | mod `elemModuleSet` imp_pkg_mods -- Case (b)
+ = go_for_it (Everything mod_vers)
+
+ | import_all_mod -- Case (a) and (b); the import-all part
+ = if is_home_pkg_mod then
+ go_for_it (Specifically mod_vers (Just export_vers) [] rules_vers)
+ else
+ go_for_it (Everything mod_vers)
+
+ | is_home_pkg_mod || has_orphans -- Case (c) or (d)
+ = go_for_it NothingAtAll
+
+ | otherwise = so_far
+ where
+ go_for_it exports = (mod_name, has_orphans, mi_boot iface, exports) : so_far
+
+ mod = mi_module iface
+ mod_name = moduleName mod
+ is_home_pkg_mod = isHomeModule mod
+ version_info = mi_version iface
+ version_env = vers_decls version_info
+ mod_vers = vers_module version_info
+ rules_vers = vers_rules version_info
+ export_vers = vers_exports version_info
+ import_all_mod = mod_name `elem` import_all_mods
+ has_orphans = mi_orphan iface
+
+ -- The sort is to put them into canonical order
+ mk_import_items ns = [(n,v) | n <- sortLt lt_occ ns,
+ let v = lookupNameEnv version_env n `orElse`
+ pprPanic "mk_whats_imported" (ppr n)
+ ]
+ where
+ lt_occ n1 n2 = nameOccName n1 < nameOccName n2
+
+ maybe_export_vers | import_all_mod = Just (vers_exports version_info)
+ | otherwise = Nothing
+ in
+ returnRn import_info
+\end{code}
+%*********************************************************
+%* *
+\subsection{Slurping declarations}
+%* *
+%*********************************************************
\begin{code}
-cachedIface :: IfaceCache
- -> Bool -- True => want merged interface for original name
- -- False => want file interface only
- -> FAST_STRING -- item that prompted search (debugging only!)
- -> Module
- -> IO (MaybeErr ParsedIface Error)
-
-cachedIface (IfaceCache _ _ iface_var) want_orig_iface item modname
- = readVar iface_var ST_THEN \ (iface_fm, orig_fm, file_fm) ->
-
- case (lookupFM iface_fm modname) of
- Just iface -> return (want_iface iface orig_fm)
- Nothing ->
- case (lookupFM file_fm modname) of
- Nothing -> return (Failed (noIfaceErr modname))
- Just file ->
- readIface file modname item >>= \ read_iface ->
- case read_iface of
- Failed err -> -- pprTrace "module-file map:\n" (ppAboves [ppCat [ppPStr m, ppStr f] | (m,f) <- fmToList file_fm]) $
- return (Failed err)
- Succeeded iface ->
- let
- iface_fm' = addToFM iface_fm modname iface
- orig_fm' = addToFM_C mergeIfaces orig_fm (iface_mod iface) iface
- in
- writeVar iface_var (iface_fm', orig_fm', file_fm) ST_THEN \ _ ->
- return (want_iface iface orig_fm')
- where
- want_iface iface orig_fm
- | want_orig_iface
- = case lookupFM orig_fm modname of
- Nothing -> Failed (noOrigIfaceErr modname)
- Just orig_iface -> Succeeded orig_iface
- | otherwise
- = Succeeded iface
-
- iface_mod (ParsedIface mod _ _ _ _ _ _ _ _ _ _ _ _) = mod
-
-----------
-mergeIfaces (ParsedIface mod1 (_, files1) _ _ _ _ _ _ fixes1 tdefs1 vdefs1 idefs1 prags1)
- (ParsedIface mod2 (_, files2) _ _ _ _ _ _ fixes2 tdefs2 vdefs2 idefs2 prags2)
- = --pprTrace "mergeIfaces:" (ppCat [ppStr "import", ppCat (map ppPStr (bagToList files2)),
- -- ppStr "merged with", ppPStr mod1]) $
- ASSERT(mod1 == mod2)
- ParsedIface mod1
- (True, unionBags files2 files1)
- (panic "mergeIface: module version numbers")
- (panic "mergeIface: source version numbers") -- Version numbers etc must be extracted from
- (panic "mergeIface: usage version numbers") -- the merged file interfaces named above
- (panic "mergeIface: decl version numbers")
- (panic "mergeIface: exports")
- (panic "mergeIface: instance modules")
- (plusFM_C (dup_merge {-"fixity" (ppr PprDebug . fixDeclName)-}) fixes1 fixes2)
- (plusFM_C (dup_merge {-"tycon/class" (ppr PprDebug . idecl_nm)-}) tdefs1 tdefs2)
- (plusFM_C (dup_merge {-"value" (ppr PprDebug . idecl_nm)-}) vdefs1 vdefs2)
- (unionBags idefs1 idefs2)
- (plusFM_C (dup_merge {-"pragma" ppStr-}) prags1 prags2)
- where
- dup_merge {-str ppr_dup-} dup1 dup2
- = --pprTrace "mergeIfaces:"
- -- (ppCat [ppPStr mod1, ppPStr mod2, ppStr ": dup", ppStr str, ppStr "decl",
- -- ppr_dup dup1, ppr_dup dup2]) $
- dup2
-
- idecl_nm (TypeSig n _ _) = n
- idecl_nm (NewTypeSig n _ _ _) = n
- idecl_nm (DataSig n _ _ _ _) = n
- idecl_nm (ClassSig n _ _ _) = n
- idecl_nm (ValSig n _ _) = n
-
-----------
-data CachingResult
- = CachingFail Error -- tried to find a decl, something went wrong
- | CachingHit RdrIfaceDecl -- got it
- | CachingAvoided (Maybe (Either RnName RnName))
- -- didn't look in the interface
- -- file(s); Nothing => the thing
- -- *should* be in the source module;
- -- Just (Left ...) => builtin val name;
- -- Just (Right ..) => builtin tc name
-
-cachedDecl :: IfaceCache
- -> Bool -- True <=> tycon or class name
- -> OrigName
- -> IO CachingResult
-
-cachedDecl iface_cache@(IfaceCache this_mod (b_val_names,b_tc_names) _)
- class_or_tycon name@(OrigName mod str)
-
- = -- pprTrace "cachedDecl:" (ppr PprDebug name) $
- if mod == this_mod then -- some i/face has made a reference
- return (CachingAvoided Nothing) -- to something from this module
- else
- let
- b_env = if class_or_tycon then b_tc_names else b_val_names
- in
- case (lookupFM b_env name) of
- Just rn -> -- in builtins!
- return (CachingAvoided (Just ((if class_or_tycon then Right else Left) rn)))
-
- Nothing ->
- cachedIface iface_cache True str mod >>= \ maybe_iface ->
- case maybe_iface of
- Failed err -> --pprTrace "cachedDecl:fail:" (ppr PprDebug orig) $
- return (CachingFail err)
- Succeeded (ParsedIface _ _ _ _ _ _ exps _ _ tdefs vdefs _ _) ->
- case (lookupFM (if class_or_tycon then tdefs else vdefs) str) of
- Just decl -> return (CachingHit decl)
- Nothing -> return (CachingFail (noDeclInIfaceErr mod str))
-
-----------
-cachedDeclByType :: IfaceCache
- -> RnName{-NB: diff type than cachedDecl -}
- -> IO CachingResult
-
-cachedDeclByType iface_cache rn
- -- the idea is: check that, e.g., if we're given an
- -- RnClass, then we really get back a ClassDecl from
- -- the cache (not an RnData, or something silly)
- = cachedDecl iface_cache (isRnTyConOrClass rn) (origName "cachedDeclByType" rn) >>= \ maybe_decl ->
- let
- return_maybe_decl = return maybe_decl
- return_failed msg = return (CachingFail msg)
- in
- case maybe_decl of
- CachingAvoided _ -> return_maybe_decl
- CachingFail io_msg -> return_failed (ifaceIoErr io_msg rn)
- CachingHit if_decl ->
- case rn of
- WiredInId _ -> return_failed (ifaceLookupWiredErr "value" rn)
- WiredInTyCon _ -> return_failed (ifaceLookupWiredErr "type constructor" rn)
- RnUnbound _ -> panic "cachedDeclByType:" -- (ppr PprDebug rn)
-
- RnSyn _ -> return_maybe_decl
- RnData _ _ _ -> return_maybe_decl
- RnImplicitTyCon _ -> if is_tycon_decl if_decl
- then return_maybe_decl
- else return_failed (badIfaceLookupErr "type constructor" rn if_decl)
-
- RnClass _ _ -> return_maybe_decl
- RnImplicitClass _ -> if is_class_decl if_decl
- then return_maybe_decl
- else return_failed (badIfaceLookupErr "class" rn if_decl)
-
- RnName _ -> return_maybe_decl
- RnConstr _ _ -> return_maybe_decl
- RnField _ _ -> return_maybe_decl
- RnClassOp _ _ -> return_maybe_decl
- RnImplicit _ -> if is_val_decl if_decl
- then return_maybe_decl
- else return_failed (badIfaceLookupErr "value" rn if_decl)
+-------------------------------------------------------
+slurpImpDecls source_fvs
+ = traceRn (text "slurpImp" <+> fsep (map ppr (nameSetToList source_fvs))) `thenRn_`
+
+ -- The current slurped-set records all local things
+ slurpSourceRefs source_fvs `thenRn` \ (decls, needed) ->
+
+ -- Then get everything else
+ closeDecls decls needed
+
+
+-------------------------------------------------------
+slurpSourceRefs :: FreeVars -- Variables referenced in source
+ -> RnMG ([RenamedHsDecl],
+ FreeVars) -- Un-satisfied needs
+-- The declaration (and hence home module) of each gate has
+-- already been loaded
+
+slurpSourceRefs source_fvs
+ = go_outer [] -- Accumulating decls
+ emptyFVs -- Unsatisfied needs
+ emptyFVs -- Accumulating gates
+ (nameSetToList source_fvs) -- Things whose defn hasn't been loaded yet
where
- is_tycon_decl (TypeSig _ _ _) = True
- is_tycon_decl (NewTypeSig _ _ _ _) = True
- is_tycon_decl (DataSig _ _ _ _ _) = True
- is_tycon_decl _ = False
-
- is_class_decl (ClassSig _ _ _ _) = True
- is_class_decl _ = False
-
- is_val_decl (ValSig _ _ _) = True
- is_val_decl (DataSig _ _ _ _ _) = True -- may be a constr or field
- is_val_decl (NewTypeSig _ _ _ _) = True -- may be a constr
- is_val_decl (ClassSig _ _ _ _) = True -- may be a method
- is_val_decl _ = False
+ -- The outer loop repeatedly slurps the decls for the current gates
+ -- and the instance decls
+
+ -- The outer loop is needed because consider
+
+ go_outer decls fvs all_gates []
+ = returnRn (decls, fvs)
+
+ go_outer decls fvs all_gates refs -- refs are not necessarily slurped yet
+ = traceRn (text "go_outer" <+> ppr refs) `thenRn_`
+ foldlRn go_inner (decls, fvs, emptyFVs) refs `thenRn` \ (decls1, fvs1, gates1) ->
+ getImportedInstDecls (all_gates `plusFV` gates1) `thenRn` \ inst_decls ->
+ rnIfaceInstDecls decls1 fvs1 gates1 inst_decls `thenRn` \ (decls2, fvs2, gates2) ->
+ go_outer decls2 fvs2 (all_gates `plusFV` gates2)
+ (nameSetToList (gates2 `minusNameSet` all_gates))
+ -- Knock out the all_gates because even if we don't slurp any new
+ -- decls we can get some apparently-new gates from wired-in names
+
+ go_inner (decls, fvs, gates) wanted_name
+ = importDecl wanted_name `thenRn` \ import_result ->
+ case import_result of
+ AlreadySlurped -> returnRn (decls, fvs, gates)
+ InTypeEnv ty_thing -> returnRn (decls, fvs, gates `plusFV` getWiredInGates ty_thing)
+
+ HereItIs decl -> rnIfaceTyClDecl decl `thenRn` \ (new_decl, fvs1) ->
+ returnRn (TyClD new_decl : decls,
+ fvs1 `plusFV` fvs,
+ gates `plusFV` getGates source_fvs new_decl)
\end{code}
+
\begin{code}
-readIface :: FilePath -> Module -> FAST_STRING -> IO (MaybeErr ParsedIface Error)
-
-readIface file modname item
- = --hPutStr stderr (" reading "++file++" ("++ _UNPK_ item ++")") >>
- TRY_IO (readFile file) >>= \ read_result ->
- case read_result of
- Left err -> return (Failed (cannaeReadErr file err))
- Right contents -> --hPutStr stderr ".." >>
- let parsed = parseIface contents in
- --hPutStr stderr "..\n" >>
- return (
- case parsed of
- Failed _ -> parsed
- Succeeded p -> Succeeded (init_merge modname p)
- )
+-------------------------------------------------------
+-- closeDecls keeps going until the free-var set is empty
+closeDecls decls needed
+ | not (isEmptyFVs needed)
+ = slurpDecls decls needed `thenRn` \ (decls1, needed1) ->
+ closeDecls decls1 needed1
+
+ | otherwise
+ = getImportedRules `thenRn` \ rule_decls ->
+ case rule_decls of
+ [] -> returnRn decls -- No new rules, so we are done
+ other -> rnIfaceDecls rnIfaceRuleDecl rule_decls `thenRn` \ rule_decls' ->
+ let
+ rule_fvs = plusFVs (map ruleDeclFVs rule_decls')
+ in
+ traceRn (text "closeRules" <+> ppr rule_decls' $$ fsep (map ppr (nameSetToList rule_fvs))) `thenRn_`
+ closeDecls (map RuleD rule_decls' ++ decls) rule_fvs
+
+
+
+-------------------------------------------------------
+-- Augment decls with any decls needed by needed.
+-- Return also free vars of the new decls (only)
+slurpDecls decls needed
+ = go decls emptyFVs (nameSetToList needed)
where
- init_merge this (ParsedIface mod _ v sv us vs exps insts fixes tdefs vdefs idefs prags)
- = ParsedIface mod (False, unitBag this) v sv us vs exps insts fixes tdefs vdefs idefs prags
+ go decls fvs [] = returnRn (decls, fvs)
+ go decls fvs (ref:refs) = slurpDecl decls fvs ref `thenRn` \ (decls1, fvs1) ->
+ go decls1 fvs1 refs
+
+-------------------------------------------------------
+slurpDecl decls fvs wanted_name
+ = importDecl wanted_name `thenRn` \ import_result ->
+ case import_result of
+ -- Found a declaration... rename it
+ HereItIs decl -> rnIfaceTyClDecl decl `thenRn` \ (new_decl, fvs1) ->
+ returnRn (TyClD new_decl:decls, fvs1 `plusFV` fvs)
+
+ -- No declaration... (wired in thing, or deferred, or already slurped)
+ other -> returnRn (decls, fvs)
+
+
+-------------------------------------------------------
+rnIfaceDecls rn decls = mapRn (rnIfaceDecl rn) decls
+rnIfaceDecl rn (mod, decl) = initIfaceRnMS mod (rn decl)
+
+rnIfaceInstDecls decls fvs gates inst_decls
+ = rnIfaceDecls rnInstDecl inst_decls `thenRn` \ inst_decls' ->
+ returnRn (map InstD inst_decls' ++ decls,
+ fvs `plusFV` plusFVs (map instDeclFVs inst_decls'),
+ gates `plusFV` plusFVs (map getInstDeclGates inst_decls'))
+
+rnIfaceTyClDecl (mod, decl) = initIfaceRnMS mod (rnTyClDecl decl) `thenRn` \ decl' ->
+ returnRn (decl', tyClDeclFVs decl')
\end{code}
\begin{code}
-rnIfaces :: IfaceCache -- iface cache (mutvar)
- -> [Module] -- directly imported modules
- -> UniqSupply
- -> RnEnv -- defined (in the source) name env
- -> RnEnv -- mentioned (in the source) name env
- -> RenamedHsModule -- module to extend with iface decls
- -> [RnName] -- imported names required (really the
- -- same info as in mentioned name env)
- -- Also, all the things we may look up
- -- later by key (Unique).
- -> IO (RenamedHsModule, -- extended module
- RnEnv, -- final env (for renaming derivings)
- ImplicitEnv, -- implicit names used (for usage info)
- (UsagesMap,VersionsMap,[Module]), -- usage info
- (Bag Error, Bag Warning))
-
-rnIfaces iface_cache imp_mods us
- def_env@((dqual, dunqual, dtc_qual, dtc_unqual), dstack)
- occ_env@((qual, unqual, tc_qual, tc_unqual), stack)
- rn_module@(HsModule modname iface_version exports imports fixities
- typedecls typesigs classdecls instdecls instsigs
- defdecls binds sigs src_loc)
- todo
- = {-
- pprTrace "rnIfaces:going after:" (ppCat (map (ppr PprDebug) todo)) $
- pprTrace "rnIfaces:qual:" (ppCat [ppBesides[ppPStr m,ppChar '.',ppPStr n] | (n,m) <- keysFM qual]) $
- pprTrace "rnIfaces:unqual:" (ppCat (map ppPStr (keysFM unqual))) $
- pprTrace "rnIfaces:tc_qual:" (ppCat [ppBesides[ppPStr m,ppChar '.',ppPStr n] | (n,m) <- keysFM tc_qual]) $
- pprTrace "rnIfaces:tc_unqual:" (ppCat (map ppPStr (keysFM tc_unqual))) $
-
- pprTrace "rnIfaces:dqual:" (ppCat [ppBesides[ppPStr m,ppChar '.',ppPStr n] | (n,m) <- keysFM dqual]) $
- pprTrace "rnIfaces:dunqual:" (ppCat (map ppPStr (keysFM dunqual))) $
- pprTrace "rnIfaces:dtc_qual:" (ppCat [ppBesides[ppPStr m,ppChar '.',ppPStr n] | (n,m) <- keysFM dtc_qual]) $
- pprTrace "rnIfaces:dtc_unqual:"(ppCat (map ppPStr (keysFM dtc_unqual))) $
- -}
-
- -- do transitive closure to bring in all needed names/defns and insts:
-
- decls_and_insts todo def_env occ_env empty_return us
- >>= \ (((if_typedecls, if_classdecls, if_instdecls, if_sigs),
- if_implicits,
- if_errs_warns),
- if_final_env) ->
-
- -- finalize what we want to say we learned about the
- -- things we used
- finalIfaceInfo iface_cache modname if_final_env if_instdecls {-all_imports_used imp_mods-} >>=
- \ usage_stuff@(usage_info, version_info, instance_mods) ->
-
- return (HsModule modname iface_version exports imports fixities
- (typedecls ++ if_typedecls)
- typesigs
- (classdecls ++ if_classdecls)
- (instdecls ++ if_instdecls)
- instsigs defdecls binds
- (sigs ++ if_sigs)
- src_loc,
- if_final_env,
- if_implicits,
- usage_stuff,
- if_errs_warns)
+recordSlurp ifaces@(Ifaces { iDecls = (decls_map, n_slurped),
+ iSlurp = slurped_names,
+ iVSlurp = (imp_mods, imp_names) })
+ avail
+ = ASSERT2( not (isLocalName (availName avail)), ppr avail )
+ ifaces { iDecls = (decls_map', n_slurped+1),
+ iSlurp = new_slurped_names,
+ iVSlurp = new_vslurp }
where
- decls_and_insts todo def_env occ_env to_return us
- = let
- (us1,us2) = splitUniqSupply us
- in
- do_decls todo -- initial batch of names to process
- (def_env, occ_env, us1) -- init stuff down
- to_return -- acc results
- >>= \ (decls_return,
- decls_def_env,
- decls_occ_env) ->
-
- cacheInstModules iface_cache imp_mods >>= \ errs ->
-
- do_insts decls_def_env decls_occ_env emptyRnEnv emptyFM
- (add_errs errs decls_return) us2
-
- --------
- do_insts def_env occ_env prev_env done_insts to_return us
- | size_tc_env occ_env == size_tc_env prev_env
- = return (to_return, occ_env)
-
- | otherwise
- = rnIfaceInstStuff iface_cache modname us1 occ_env done_insts to_return
- >>= \ (insts_return,
- new_insts,
- insts_occ_env,
- new_unknowns) ->
-
- do_decls new_unknowns -- new batch of names to process
- (def_env, insts_occ_env, us2) -- init stuff down
- insts_return -- acc results
- >>= \ (decls_return,
- decls_def_env,
- decls_occ_env) ->
-
- do_insts decls_def_env decls_occ_env occ_env new_insts decls_return us3
- where
- (us1,us') = splitUniqSupply us
- (us2,us3) = splitUniqSupply us'
-
- size_tc_env ((_, _, qual, unqual), _)
- = sizeFM qual + sizeFM unqual
-
-
- do_decls :: [RnName] -- Names we're looking for; we keep adding/deleting
- -- from this list; we're done when empty (nothing
- -- more needs to be looked for)
- -> Go_Down -- see defn below
- -> To_Return -- accumulated result
- -> IO (To_Return,
- RnEnv, -- extended decl env
- RnEnv) -- extended occ env
-
- do_decls to_find@[] down to_return
- = return (to_return, defenv down, occenv down)
-
- do_decls to_find@(n:ns) down to_return
- = case (lookup_defd down n) of
- Just _ -> -- previous processing must've found the stuff for this name;
- -- continue with the rest:
- -- pprTrace "do_decls:done:" (ppr PprDebug n) $
- do_decls ns down to_return
-
- Nothing
- | moduleOf (origName "do_decls" n) == modname ->
- -- avoid looking in interface for the module being compiled
- --pprTrace "do_decls:this module error:" (ppr PprDebug n) $
- do_decls ns down (add_warn (thisModImplicitWarn modname n) to_return)
-
- | otherwise ->
- -- OK, see what the cache has for us...
-
- cachedDeclByType iface_cache n >>= \ maybe_ans ->
- case maybe_ans of
- CachingAvoided _ ->
- --pprTrace "do_decls:caching avoided:" (ppr PprDebug n) $
- do_decls ns down to_return
-
- CachingFail err -> -- add the error, but keep going:
- --pprTrace "do_decls:cache error:" (ppr PprDebug n) $
- do_decls ns down (add_err err to_return)
-
- CachingHit iface_decl -> -- something needing renaming!
- let
- (us1, us2) = splitUniqSupply (uniqsupply down)
- in
- case (initRn False{-iface-} modname (occenv down) us1 (
- setExtraRn emptyUFM{-no fixities-} $
- rnIfaceDecl iface_decl)) of {
- ((if_decl, if_defd, if_implicits), if_errs, if_warns) ->
- let
- new_unknowns = eltsFM (fst if_implicits) ++ eltsFM (snd if_implicits)
- in
- {-
- pprTrace "do_decls:renamed:" (ppAboves [ppr PprDebug n
- , ppCat [ppStr "new unknowns:", interpp'SP PprDebug new_unknowns]
- , ppCat [ppStr "defd vals:", interpp'SP PprDebug [n | (_,n) <- fst if_defd] ]
- , ppCat [ppStr "defd tcs:", interpp'SP PprDebug [n | (_,n) <- snd if_defd] ]
- ]) $
- -}
- do_decls (new_unknowns ++ ns)
- (add_occs if_defd if_implicits $
- new_uniqsupply us2 down)
- (add_decl if_decl $
- add_implicits if_implicits $
- add_errs if_errs $
- add_warns if_warns to_return)
- }
-
------------
-type Go_Down = (RnEnv, -- stuff we already have defns for;
- -- to check quickly if we've already
- -- found something for the name under consideration,
- -- due to previous processing.
- -- It starts off just w/ the defns for
- -- the things in this module.
- RnEnv, -- occurrence env; this gets added to as
- -- we process new iface decls. It includes
- -- entries for *all* occurrences, including those
- -- for which we have definitions.
- UniqSupply -- the obvious
- )
-
-lookup_defd (def_env, _, _) n
- = (if isRnTyConOrClass n then lookupTcRnEnv else lookupRnEnv) def_env
- (case (origName "lookup_defd" n) of { OrigName m s -> Qual m s })
- -- this is hack because we are reusing the RnEnv technology
-
-defenv (def_env, _, _) = def_env
-occenv (_, occ_env, _) = occ_env
-uniqsupply (_, _, us) = us
-
-new_uniqsupply us (def_env, occ_env, _) = (def_env, occ_env, us)
-
-add_occs (val_defds, tc_defds) (val_imps, tc_imps) (def_env, occ_env, us)
- = case (extendGlobalRnEnv def_env val_defds tc_defds) of { (new_def_env, def_dups) ->
- --(if isEmptyBag def_dups then \x->x else pprTrace "add_occs:" (ppCat [ppr PprDebug n | (n,_,_) <- bagToList def_dups])) $
--- ASSERT(isEmptyBag def_dups)
- let
- de_orig imps = [ (Qual m n, v) | (OrigName m n, v) <- fmToList imps ]
- -- again, this hackery because we are reusing the RnEnv technology
+ decls_map' = foldl delFromNameEnv decls_map (availNames avail)
+ main_name = availName avail
+ mod = nameModule main_name
+ new_slurped_names = addAvailToNameSet slurped_names avail
+ new_vslurp | isHomeModule mod = (imp_mods, addOneToNameSet imp_names main_name)
+ | otherwise = (extendModuleSet imp_mods mod, imp_names)
+
+recordLocalSlurps new_names
+ = getIfacesRn `thenRn` \ ifaces ->
+ setIfacesRn (ifaces { iSlurp = iSlurp ifaces `unionNameSets` new_names })
+\end{code}
- val_occs = val_defds ++ de_orig val_imps
- tc_occs = tc_defds ++ de_orig tc_imps
- in
- case (extendGlobalRnEnv occ_env val_occs tc_occs) of { (new_occ_env, occ_dups) ->
--- ASSERT(isEmptyBag occ_dups)
--- False because we may get a dup on the name we just shoved in
- (new_def_env, new_occ_env, us) }}
+%*********************************************************
+%* *
+\subsection{Extracting the `gates'}
+%* *
+%*********************************************************
+
+The gating story
+~~~~~~~~~~~~~~~~~
+We want to avoid sucking in too many instance declarations.
+An instance decl is only useful if the types and classes mentioned in
+its 'head' are all available in the program being compiled. E.g.
+
+ instance (..) => C (T1 a) (T2 b) where ...
+
+is only useful if C, T1 and T2 are all "available". So we keep
+instance decls that have been parsed from .hi files, but not yet
+slurped in, in a pool called the 'gated instance pool'.
+Each has its set of 'gates': {C, T1, T2} in the above example.
+
+More precisely, the gates of a module are the types and classes
+that are mentioned in:
+
+ a) the source code
+ b) the type of an Id that's mentioned in the source code
+ [includes constructors and selectors]
+ c) the RHS of a type synonym that is a gate
+ d) the superclasses of a class that is a gate
+ e) the context of an instance decl that is slurped in
-----------------
-type To_Return = (([RenamedTyDecl], [RenamedClassDecl], [RenamedInstDecl], [RenamedSig]),
- ImplicitEnv, -- new names used implicitly
- (Bag Error, Bag Warning)
- )
+We slurp in an instance decl from the gated instance pool iff
+
+ all its gates are either in the gates of the module,
+ or are a previously-loaded class.
-empty_return :: To_Return
-empty_return = (([],[],[],[]), emptyImplicitEnv, (emptyBag,emptyBag))
+The latter constraint is because there might have been an instance
+decl slurped in during an earlier compilation, like this:
-add_decl decl ((tydecls, classdecls, instdecls, sigs), implicit, msgs)
- = case decl of
- AddedTy t -> ((t:tydecls, classdecls, instdecls, sigs), implicit, msgs)
- AddedClass c -> ((tydecls, c:classdecls, instdecls, sigs), implicit, msgs)
- AddedSig s -> ((tydecls, classdecls, instdecls, s:sigs), implicit, msgs)
+ instance Foo a => Baz (Maybe a) where ...
-add_insts is ((tydecls, classdecls, instdecls, sigs), implicit, msgs)
- = ((tydecls, classdecls, is ++ instdecls, sigs), implicit, msgs)
+In the module being compiled we might need (Baz (Maybe T)), where T
+is defined in this module, and hence we need (Foo T). So @Foo@ becomes
+a gate. But there's no way to 'see' that, so we simply treat all
+previously-loaded classes as gates.
-add_implicits (val_imps, tc_imps) (decls, (val_fm, tc_fm), msgs)
- = (decls, (val_fm `plusFM` val_imps, tc_fm `plusFM` tc_imps), msgs)
+Consructors and class operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When we import a declaration like
+
+ data T = T1 Wibble | T2 Wobble
+
+we don't want to treat @Wibble@ and @Wobble@ as gates {\em unless}
+@T1@, @T2@ respectively are mentioned by the user program. If only
+@T@ is mentioned we want only @T@ to be a gate; that way we don't suck
+in useless instance decls for (say) @Eq Wibble@, when they can't
+possibly be useful.
+
+And that's just what (b) says: we only treat T1's type as a gate if
+T1 is mentioned. getGates, which deals with decls we are slurping in,
+has to be a bit careful, because a mention of T1 will slurp in T's whole
+declaration.
+
+-----------------------------
+@getGates@ takes a newly imported (and renamed) decl, and the free
+vars of the source program, and extracts from the decl the gate names.
+
+\begin{code}
+getGates :: FreeVars -- Things mentioned in the source program
+ -> RenamedTyClDecl
+ -> FreeVars
-add_err err (decls,implicit,(errs,warns)) = (decls,implicit,(errs `snocBag` err,warns))
-add_errs ers (decls,implicit,(errs,warns)) = (decls,implicit,(errs `unionBags` ers,warns))
-add_warn wrn (decls,implicit,(errs,warns)) = (decls,implicit,(errs, warns `snocBag` wrn))
-add_warns ws (decls,implicit,(errs,warns)) = (decls,implicit,(errs, warns `unionBags` ws))
+getGates source_fvs decl
+ = get_gates (\n -> n `elemNameSet` source_fvs) decl
+
+get_gates is_used (IfaceSig {tcdType = ty}) = extractHsTyNames ty
+
+get_gates is_used (ClassDecl { tcdCtxt = ctxt, tcdName = cls, tcdTyVars = tvs, tcdSigs = sigs})
+ = (delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) sigs)
+ (hsTyVarNames tvs)
+ `addOneToNameSet` cls)
+ `plusFV` maybe_double
+ where
+ get (ClassOpSig n _ ty _)
+ | is_used n = extractHsTyNames ty
+ | otherwise = emptyFVs
+
+ -- If we load any numeric class that doesn't have
+ -- Int as an instance, add Double to the gates.
+ -- This takes account of the fact that Double might be needed for
+ -- defaulting, but we don't want to load Double (and all its baggage)
+ -- if the more exotic classes aren't used at all.
+ maybe_double | nameUnique cls `elem` fractionalClassKeys
+ = unitFV (getName doubleTyCon)
+ | otherwise
+ = emptyFVs
+
+get_gates is_used (TySynonym {tcdTyVars = tvs, tcdSynRhs = ty})
+ = delListFromNameSet (extractHsTyNames ty) (hsTyVarNames tvs)
+ -- A type synonym type constructor isn't a "gate" for instance decls
+
+get_gates is_used (TyData {tcdCtxt = ctxt, tcdName = tycon, tcdTyVars = tvs, tcdCons = cons})
+ = delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) cons)
+ (hsTyVarNames tvs)
+ `addOneToNameSet` tycon
+ where
+ get (ConDecl n _ tvs ctxt details _)
+ | is_used n
+ -- If the constructor is method, get fvs from all its fields
+ = delListFromNameSet (get_details details `plusFV`
+ extractHsCtxtTyNames ctxt)
+ (hsTyVarNames tvs)
+ get (ConDecl n _ tvs ctxt (RecCon fields) _)
+ -- Even if the constructor isn't mentioned, the fields
+ -- might be, as selectors. They can't mention existentially
+ -- bound tyvars (typechecker checks for that) so no need for
+ -- the deleteListFromNameSet part
+ = foldr (plusFV . get_field) emptyFVs fields
+
+ get other_con = emptyFVs
+
+ get_details (VanillaCon tys) = plusFVs (map get_bang tys)
+ get_details (InfixCon t1 t2) = get_bang t1 `plusFV` get_bang t2
+ get_details (RecCon fields) = plusFVs [get_bang t | (_, t) <- fields]
+
+ get_field (fs,t) | any is_used fs = get_bang t
+ | otherwise = emptyFVs
+
+ get_bang bty = extractHsTyNames (getBangType bty)
\end{code}
+@getWiredInGates@ is just like @getGates@, but it sees a previously-loaded
+thing rather than a declaration.
+
\begin{code}
-data AddedDecl -- purely local
- = AddedTy RenamedTyDecl
- | AddedClass RenamedClassDecl
- | AddedSig RenamedSig
-
-rnIfaceDecl :: RdrIfaceDecl
- -> RnM_Fixes REAL_WORLD
- (AddedDecl, -- the resulting decl to add to the pot
- ([(RdrName,RnName)], [(RdrName,RnName)]),
- -- new val/tycon-class names that have
- -- *been defined* while processing this decl
- ImplicitEnv -- new implicit val/tycon-class names that we
- -- stumbled into
- )
-
-rnIfaceDecl (TypeSig tc _ decl)
- = rnTyDecl decl `thenRn` \ rn_decl ->
- lookupTyCon tc `thenRn` \ rn_tc ->
- getImplicitUpRn `thenRn` \ mentioned ->
- let
- defds = ([], [(tc, rn_tc)])
- implicits = mentioned `sub` defds
- in
- returnRn (AddedTy rn_decl, defds, implicits)
+getWiredInGates :: TyThing -> FreeVars
+-- The TyThing is one that we already have in our type environment, either
+-- a) because the TyCon or Id is wired in, or
+-- b) from a previous compile
+-- Either way, we might have instance decls in the (persistent) collection
+-- of parsed-but-not-slurped instance decls that should be slurped in.
+-- This might be the first module that mentions both the type and the class
+-- for that instance decl, even though both the type and the class were
+-- mentioned in other modules, and hence are in the type environment
+
+getWiredInGates (AnId the_id) = namesOfType (idType the_id)
+getWiredInGates (AClass cl) = emptyFVs -- The superclasses must also be previously
+ -- loaded, and hence are automatically gates
+getWiredInGates (ATyCon tc)
+ | isSynTyCon tc = delListFromNameSet (namesOfType ty) (map getName tyvars)
+ | otherwise = unitFV (getName tc)
+ where
+ (tyvars,ty) = getSynTyConDefn tc
+
+getInstDeclGates (InstDecl inst_ty _ _ _ _) = extractHsTyNames inst_ty
+\end{code}
-rnIfaceDecl (NewTypeSig tc dc _ decl)
- = rnTyDecl decl `thenRn` \ rn_decl ->
- lookupTyCon tc `thenRn` \ rn_tc ->
- lookupValue dc `thenRn` \ rn_dc ->
- getImplicitUpRn `thenRn` \ mentioned ->
+\begin{code}
+getImportedInstDecls :: NameSet -> RnMG [(Module,RdrNameInstDecl)]
+getImportedInstDecls gates
+ = -- First, load any orphan-instance modules that aren't aready loaded
+ -- Orphan-instance modules are recorded in the module dependecnies
+ getIfacesRn `thenRn` \ ifaces ->
let
- defds = ([(dc, rn_dc)], [(tc, rn_tc)])
- implicits = mentioned `sub` defds
+ orphan_mods =
+ [mod | (mod, (True, _)) <- fmToList (iImpModInfo ifaces)]
in
- returnRn (AddedTy rn_decl, defds, implicits)
-
-rnIfaceDecl (DataSig tc dcs fcs _ decl)
- = rnTyDecl decl `thenRn` \ rn_decl ->
- lookupTyCon tc `thenRn` \ rn_tc ->
- mapRn lookupValue dcs `thenRn` \ rn_dcs ->
- mapRn lookupValue fcs `thenRn` \ rn_fcs ->
- getImplicitUpRn `thenRn` \ mentioned ->
+ loadOrphanModules orphan_mods `thenRn_`
+
+ -- Now we're ready to grab the instance declarations
+ -- Find the un-gated ones and return them,
+ -- removing them from the bag kept in Ifaces
+ getIfacesRn `thenRn` \ ifaces ->
+ getTypeEnvRn `thenRn` \ lookup ->
let
- defds = (zip dcs rn_dcs ++ zip fcs rn_fcs , [(tc, rn_tc)])
- implicits = mentioned `sub` defds
+ (decls, new_insts) = selectGated gates lookup (iInsts ifaces)
in
- returnRn (AddedTy rn_decl, defds, implicits)
+ setIfacesRn (ifaces { iInsts = new_insts }) `thenRn_`
-rnIfaceDecl (ClassSig clas ops _ decl)
- = rnClassDecl decl `thenRn` \ rn_decl ->
- lookupClass clas `thenRn` \ rn_clas ->
- mapRn (lookupClassOp rn_clas) ops `thenRn` \ rn_ops ->
- getImplicitUpRn `thenRn` \ mentioned ->
+ traceRn (sep [text "getImportedInstDecls:",
+ nest 4 (fsep (map ppr gate_list)),
+ text "Slurped" <+> int (length decls) <+> text "instance declarations",
+ nest 4 (vcat (map ppr_brief_inst_decl decls))]) `thenRn_`
+ returnRn decls
+ where
+ gate_list = nameSetToList gates
+
+ppr_brief_inst_decl (mod, InstDecl inst_ty _ _ _ _)
+ = case inst_ty of
+ HsForAllTy _ _ tau -> ppr tau
+ other -> ppr inst_ty
+
+getImportedRules :: RnMG [(Module,RdrNameRuleDecl)]
+getImportedRules
+ | opt_IgnoreIfacePragmas = returnRn []
+ | otherwise
+ = getIfacesRn `thenRn` \ ifaces ->
+ getTypeEnvRn `thenRn` \ lookup ->
let
- defds = (ops `zip` rn_ops, [(clas, rn_clas)])
- implicits = mentioned `sub` defds
+ gates = iSlurp ifaces -- Anything at all that's been slurped
+ rules = iRules ifaces
+ (decls, new_rules) = selectGated gates lookup rules
in
- returnRn (AddedClass rn_decl, defds, implicits)
-
-rnIfaceDecl (ValSig f src_loc ty)
- -- should rename_sig in RnBinds be used here? ToDo
- = lookupValue f `thenRn` \ rn_f ->
- -- pprTrace "rnIfaceDecl:ValSig:" (ppr PprDebug ty) $
- rnPolyType nullTyVarNamesEnv ty `thenRn` \ rn_ty ->
- getImplicitUpRn `thenRn` \ mentioned ->
- let
- defds = ([(f, rn_f)], [])
- implicits = mentioned `sub` defds
+ if null decls then
+ returnRn []
+ else
+ setIfacesRn (ifaces { iRules = new_rules }) `thenRn_`
+ traceRn (sep [text "getImportedRules:",
+ text "Slurped" <+> int (length decls) <+> text "rules"]) `thenRn_`
+ returnRn decls
+
+selectGated gates lookup (decl_bag, n_slurped)
+ -- Select only those decls whose gates are *all* in 'gates'
+ -- or are a class in 'lookup'
+#ifdef DEBUG
+ | opt_NoPruneDecls -- Just to try the effect of not gating at all
+ = let
+ decls = foldrBag (\ (_,d) ds -> d:ds) [] decl_bag -- Grab them all
in
- returnRn (AddedSig (Sig rn_f rn_ty noGenPragmas src_loc), defds, implicits)
+ (decls, (emptyBag, n_slurped + length decls))
-----
-sub :: ImplicitEnv -> ([(RdrName,RnName)], [(RdrName,RnName)]) -> ImplicitEnv
+ | otherwise
+#endif
+ = case foldrBag select ([], emptyBag) decl_bag of
+ (decls, new_bag) -> (decls, (new_bag, n_slurped + length decls))
+ where
+ available n = n `elemNameSet` gates
+ || case lookup n of { Just (AClass c) -> True; other -> False }
-sub (val_ment, tc_ment) (val_defds, tc_defds)
- = (delListFromFM val_ment (map (qualToOrigName . fst) val_defds),
- delListFromFM tc_ment (map (qualToOrigName . fst) tc_defds))
+ select (reqd, decl) (yes, no)
+ | all available reqd = (decl:yes, no)
+ | otherwise = (yes, (reqd,decl) `consBag` no)
\end{code}
-% ------------------------------
-@cacheInstModules@: cache instance modules specified in imports
+%*********************************************************
+%* *
+\subsection{Getting in a declaration}
+%* *
+%*********************************************************
\begin{code}
-cacheInstModules :: IfaceCache -> [Module] -> IO (Bag Error)
+importDecl :: Name -> RnMG ImportDeclResult
+
+data ImportDeclResult
+ = AlreadySlurped
+ | InTypeEnv TyThing
+ | HereItIs (Module, RdrNameTyClDecl)
+
+importDecl name
+ = -- STEP 1: Check if we've slurped it in while compiling this module
+ getIfacesRn `thenRn` \ ifaces ->
+ if name `elemNameSet` iSlurp ifaces then
+ returnRn AlreadySlurped
+ else
-cacheInstModules iface_cache@(IfaceCache _ _ iface_var) imp_mods
- = readVar iface_var ST_THEN \ (iface_fm, _, _) ->
- let
- imp_ifaces = [ iface | Just iface <- map (lookupFM iface_fm) imp_mods ]
- (imp_imods, _) = removeDups cmpPString (bagToList (unionManyBags (map get_ims imp_ifaces)))
- get_ims (ParsedIface _ _ _ _ _ _ _ ims _ _ _ _ _) = ims
- in
- --pprTrace "cacheInstModules:" (ppCat (map ppPStr imp_imods)) $
- accumulate (map (cachedIface iface_cache False SLIT("instance_modules")) imp_imods) >>= \ err_or_ifaces ->
+ -- STEP 2: Check if it's already in the type environment
+ getTypeEnvRn `thenRn` \ lookup ->
+ case lookup name of {
+ Just ty_thing | name `elemNameEnv` wiredInThingEnv
+ -> -- When we find a wired-in name we must load its home
+ -- module so that we find any instance decls lurking therein
+ loadHomeInterface wi_doc name `thenRn_`
+ returnRn (InTypeEnv ty_thing)
- -- Sanity Check:
- -- Assert that instance modules given by direct imports contains
- -- instance modules extracted from all visited modules
+ | otherwise
+ -> returnRn (InTypeEnv ty_thing) ;
- readVar iface_var ST_THEN \ (all_iface_fm, _, _) ->
+ Nothing ->
+
+ -- STEP 3: OK, we have to slurp it in from an interface file
+ -- First load the interface file
+ traceRn nd_doc `thenRn_`
+ loadHomeInterface nd_doc name `thenRn_`
+ getIfacesRn `thenRn` \ ifaces ->
+
+ -- STEP 4: Get the declaration out
let
- all_ifaces = eltsFM all_iface_fm
- (all_imods, _) = removeDups cmpPString (bagToList (unionManyBags (map get_ims (all_ifaces))))
+ (decls_map, _) = iDecls ifaces
in
- ASSERT(sortLt (<) imp_imods == sortLt (<) all_imods)
-
- return (bag_errs err_or_ifaces)
+ case lookupNameEnv decls_map name of
+ Just (avail,_,decl)
+ -> setIfacesRn (recordSlurp ifaces avail) `thenRn_`
+ returnRn (HereItIs decl)
+
+ Nothing
+ -> addErrRn (getDeclErr name) `thenRn_`
+ returnRn AlreadySlurped
+ }
where
- bag_errs [] = emptyBag
- bag_errs (Failed err :rest) = err `consBag` bag_errs rest
- bag_errs (Succeeded _:rest) = bag_errs rest
+ wi_doc = ptext SLIT("need home module for wired in thing") <+> ppr name
+ nd_doc = ptext SLIT("need decl for") <+> ppr name
+
\end{code}
-@rnIfaceInstStuff@: Deal with instance declarations from interface files.
+%********************************************************
+%* *
+\subsection{Checking usage information}
+%* *
+%********************************************************
-\begin{code}
-type InstanceEnv = FiniteMap (OrigName, OrigName) Int
-
-rnIfaceInstStuff
- :: IfaceCache -- all about ifaces we've read
- -> Module
- -> UniqSupply
- -> RnEnv -- current occ env
- -> InstanceEnv -- instances for these tycon/class pairs done
- -> To_Return
- -> IO (To_Return,
- InstanceEnv, -- extended instance env
- RnEnv, -- final occ env
- [RnName]) -- new unknown names
-
-rnIfaceInstStuff iface_cache@(IfaceCache _ _ iface_var) modname us occ_env done_inst_env to_return
- = -- all the instance decls we might even want to consider
- -- are in the ParsedIfaces that are in our cache
-
- readVar iface_var ST_THEN \ (_, orig_iface_fm, _) ->
- let
- all_ifaces = eltsFM orig_iface_fm
- all_insts = concat (map get_insts all_ifaces)
- interesting_insts = filter want_inst all_insts
+@recompileRequired@ is called from the HscMain. It checks whether
+a recompilation is required. It needs access to the persistent state,
+finder, etc, because it may have to load lots of interface files to
+check their versions.
- -- Sanity Check:
- -- Assert that there are no more instances for the done instances
+\begin{code}
+type RecompileRequired = Bool
+upToDate = False -- Recompile not required
+outOfDate = True -- Recompile required
+
+recompileRequired :: FilePath -- Only needed for debug msgs
+ -> Bool -- Source unchanged
+ -> ModIface -- Old interface
+ -> RnMG RecompileRequired
+recompileRequired iface_path source_unchanged iface
+ = traceHiDiffsRn (text "Considering whether compilation is required for" <+> text iface_path <> colon) `thenRn_`
+
+ -- CHECK WHETHER THE SOURCE HAS CHANGED
+ if not source_unchanged then
+ traceHiDiffsRn (nest 4 (text "Source file changed or recompilation check turned off")) `thenRn_`
+ returnRn outOfDate
+ else
- claim_done = filter is_done_inst all_insts
- claim_done_env = foldr add_done_inst emptyFM claim_done
+ -- Source code unchanged and no errors yet... carry on
+ checkList [checkModUsage u | u <- mi_usages iface]
- has_val fm (k,i) = case lookupFM fm k of { Nothing -> False; Just v -> i == v }
- in
- {-
- pprTrace "all_insts:\n" (ppr_insts (bagToList all_insts)) $
- pprTrace "interesting_insts:\n" (ppr_insts interesting_insts) $
- -}
- ASSERT(sizeFM done_inst_env == sizeFM claim_done_env)
- ASSERT(all (has_val claim_done_env) (fmToList done_inst_env))
-
- case (initRn False{-iface-} modname occ_env us (
- setExtraRn emptyUFM{-no fixities-} $
- mapRn rnIfaceInst interesting_insts `thenRn` \ insts ->
- getImplicitUpRn `thenRn` \ implicits ->
- returnRn (insts, implicits))) of {
- ((if_insts, if_implicits), if_errs, if_warns) ->
-
- return (add_insts if_insts $
- add_implicits if_implicits $
- add_errs if_errs $
- add_warns if_warns to_return,
- foldr add_done_inst done_inst_env interesting_insts,
- add_imp_occs if_implicits occ_env,
- eltsFM (fst if_implicits) ++ eltsFM (snd if_implicits))
- }
- where
- get_insts (ParsedIface imod _ _ _ _ _ _ _ _ _ _ insts _) = [(imod, inst) | inst <- bagToList insts]
-
- tycon_class clas tycon = (qualToOrigName clas, qualToOrigName tycon)
-
- add_done_inst (_, InstSig clas tycon _ _) inst_env
- = addToFM_C (+) inst_env (tycon_class clas tycon) 1
-
- is_done_inst (_, InstSig clas tycon _ _)
- = maybeToBool (lookupFM done_inst_env (tycon_class clas tycon))
-
- add_imp_occs (val_imps, tc_imps) occ_env
- = case (extendGlobalRnEnv occ_env (de_orig val_imps) (de_orig tc_imps)) of
- (ext_occ_env, occ_dups) -> ASSERT(isEmptyBag occ_dups)
- ext_occ_env
- where
- de_orig imps = [ (Qual m n, v) | (OrigName m n, v) <- fmToList imps ]
- -- again, this hackery because we are reusing the RnEnv technology
-
- want_inst i@(imod, InstSig clas tycon _ _)
- = -- it's a "good instance" (one to hang onto) if we have a
- -- chance of referring to *both* the class and tycon later on ...
- --pprTrace "want_inst:" (ppCat [ppr PprDebug clas, ppr PprDebug tycon, ppr PprDebug (mentionable tycon), ppr PprDebug (mentionable clas), ppr PprDebug(is_done_inst i)]) $
- mentionable tycon && mentionable clas && not (is_done_inst i)
- where
- mentionable nm
- = case lookupTcRnEnv occ_env nm of
- Just _ -> True
- Nothing -> -- maybe it's builtin
- let orig = qualToOrigName nm in
- case (lookupFM builtinTcNamesMap orig) of
- Just _ -> True
- Nothing -> maybeToBool (lookupFM builtinKeysMap orig)
+checkList :: [RnMG RecompileRequired] -> RnMG RecompileRequired
+checkList [] = returnRn upToDate
+checkList (check:checks) = check `thenRn` \ recompile ->
+ if recompile then
+ returnRn outOfDate
+ else
+ checkList checks
\end{code}
-
+
\begin{code}
-rnIfaceInst :: (Module, RdrIfaceInst) -> RnM_Fixes REAL_WORLD RenamedInstDecl
+checkModUsage :: ImportVersion Name -> RnMG RecompileRequired
+-- Given the usage information extracted from the old
+-- M.hi file for the module being compiled, figure out
+-- whether M needs to be recompiled.
+
+checkModUsage (mod_name, _, _, NothingAtAll)
+ -- If CurrentModule.hi contains
+ -- import Foo :: ;
+ -- then that simply records that Foo lies below CurrentModule in the
+ -- hierarchy, but CurrentModule doesn't depend in any way on Foo.
+ -- In this case we don't even want to open Foo's interface.
+ = up_to_date (ptext SLIT("Nothing used from:") <+> ppr mod_name)
+
+checkModUsage (mod_name, _, is_boot, whats_imported)
+ = -- Load the imported interface is possible
+ -- We use tryLoadInterface, because failure is not an error
+ -- (might just be that the old .hi file for this module is out of date)
+ -- We use ImportByUser/ImportByUserSource as the 'from' flag,
+ -- a) because we need to know whether to load the .hi-boot file
+ -- b) because loadInterface things matters are amiss if we
+ -- ImportBySystem an interface it knows nothing about
+ let
+ doc_str = sep [ptext SLIT("need version info for"), ppr mod_name]
+ from | is_boot = ImportByUserSource
+ | otherwise = ImportByUser
+ in
+ tryLoadInterface doc_str mod_name from `thenRn` \ (iface, maybe_err) ->
-rnIfaceInst (imod, InstSig _ _ _ inst_decl) = rnInstDecl (inst_decl imod)
-\end{code}
+ case maybe_err of {
+ Just err -> out_of_date (sep [ptext SLIT("Can't find version number for module"),
+ ppr mod_name]) ;
+ -- Couldn't find or parse a module mentioned in the
+ -- old interface file. Don't complain -- it might just be that
+ -- the current module doesn't need that import and it's been deleted
-\begin{code}
-type BigMaps = (FiniteMap Module Version, -- module-version map
- FiniteMap (FAST_STRING,Module) Version) -- ordinary version map
-
-finalIfaceInfo ::
- IfaceCache -- iface cache
- -> Module -- this module's name
- -> RnEnv
- -> [RenamedInstDecl]
--- -> [RnName] -- all imported names required
--- -> [Module] -- directly imported modules
- -> IO (UsagesMap,
- VersionsMap, -- info about version numbers
- [Module]) -- special instance modules
-
-finalIfaceInfo iface_cache@(IfaceCache _ _ iface_var) modname if_final_env@((qual, unqual, tc_qual, tc_unqual), stack) if_instdecls
- =
--- pprTrace "usageIf:qual:" (ppCat [ppBesides[ppPStr m,ppChar '.',ppPStr n] | (n,m) <- keysFM qual]) $
--- pprTrace "usageIf:unqual:" (ppCat (map ppPStr (keysFM unqual))) $
--- pprTrace "usageIf:tc_qual:" (ppCat [ppBesides[ppPStr m,ppChar '.',ppPStr n] | (n,m) <- keysFM tc_qual]) $
--- pprTrace "usageIf:tc_unqual:" (ppCat (map ppPStr (keysFM tc_unqual))) $
- readVar iface_var ST_THEN \ (_, orig_iface_fm, _) ->
+ Nothing ->
let
- all_ifaces = eltsFM orig_iface_fm
- -- all the interfaces we have looked at
+ new_vers = mi_version iface
+ new_decl_vers = vers_decls new_vers
+ in
+ case whats_imported of { -- NothingAtAll dealt with earlier
- big_maps
- -- combine all the version maps we have seen into maps to
- -- (a) lookup a module-version number, lookup an entity's
- -- individual version number
- = foldr mk_map (emptyFM,emptyFM) all_ifaces
+ Everything old_mod_vers -> checkModuleVersion old_mod_vers new_vers `thenRn` \ recompile ->
+ if recompile then
+ out_of_date (ptext SLIT("...and I needed the whole module"))
+ else
+ returnRn upToDate ;
- val_stuff@(val_usages, val_versions)
- = foldFM (process_item big_maps) (emptyFM, emptyFM){-init-} qual
+ Specifically old_mod_vers maybe_old_export_vers old_decl_vers old_rule_vers ->
- (all_usages, all_versions)
- = foldFM (process_item big_maps) val_stuff{-keep going-} tc_qual
- in
- return (all_usages, all_versions, [])
- where
- mk_map (ParsedIface m _ mv _ _ vers _ _ _ _ _ _ _) (mv_map, ver_map)
- = (addToFM mv_map m mv, -- add this module
- addListToFM ver_map [ ((n,m), v) | (n,v) <- fmToList vers ])
-
- -----------------------
- process_item :: BigMaps
- -> (FAST_STRING,Module) -> RnName -- RnEnv (QualNames) components
- -> (UsagesMap, VersionsMap) -- input
- -> (UsagesMap, VersionsMap) -- output
-
- process_item (big_mv_map, big_version_map) key@(n,m) rn as_before@(usages, versions)
- | irrelevant rn
- = as_before
- | m == modname -- this module => add to "versions"
- = (usages, addToFM versions n 1{-stub-})
- | otherwise -- from another module => add to "usages"
- = case (add_to_usages usages key) of
- Nothing -> as_before
- Just new_usages -> (new_usages, versions)
- where
- add_to_usages usages key@(n,m)
- = case (lookupFM big_mv_map m) of
- Nothing -> Nothing
- Just mv ->
- case (lookupFM big_version_map key) of
- Nothing -> Nothing
- Just kv ->
- Just $ addToFM usages m (
- case (lookupFM usages m) of
- Nothing -> -- nothing for this module yet...
- (mv, unitFM n kv)
-
- Just (mversion, mstuff) -> -- the "new" stuff will shadow the old
- ASSERT(mversion == mv)
- (mversion, addToFM mstuff n kv)
- )
-
- irrelevant (RnConstr _ _) = True -- We don't report these in their
- irrelevant (RnField _ _) = True -- own right in usages/etc.
- irrelevant (RnClassOp _ _) = True
- irrelevant (RnImplicit n) = isLexCon (nameOf (origName "irrelevant" n)) -- really a RnConstr
- irrelevant _ = False
+ -- CHECK MODULE
+ checkModuleVersion old_mod_vers new_vers `thenRn` \ recompile ->
+ if not recompile then
+ returnRn upToDate
+ else
+
+ -- CHECK EXPORT LIST
+ if checkExportList maybe_old_export_vers new_vers then
+ out_of_date (ptext SLIT("Export list changed"))
+ else
-\end{code}
+ -- CHECK RULES
+ if old_rule_vers /= vers_rules new_vers then
+ out_of_date (ptext SLIT("Rules changed"))
+ else
+
+ -- CHECK ITEMS ONE BY ONE
+ checkList [checkEntityUsage new_decl_vers u | u <- old_decl_vers] `thenRn` \ recompile ->
+ if recompile then
+ returnRn outOfDate -- This one failed, so just bail out now
+ else
+ up_to_date (ptext SLIT("...but the bits I use haven't."))
+ }}
-\begin{code}
-thisModImplicitWarn mod n sty
- = ppBesides [ppPStr SLIT("An interface has an implicit need of "), ppr sty n, ppPStr SLIT("; assuming this module will provide it.")]
+------------------------
+checkModuleVersion old_mod_vers new_vers
+ | vers_module new_vers == old_mod_vers
+ = up_to_date (ptext SLIT("Module version unchanged"))
+
+ | otherwise
+ = out_of_date (ptext SLIT("Module version has changed"))
-noIfaceErr mod sty
- = ppCat [ppPStr SLIT("Could not find interface for:"), ppPStr mod]
+------------------------
+checkExportList Nothing new_vers = upToDate
+checkExportList (Just v) new_vers = v /= vers_exports new_vers
-noOrigIfaceErr mod sty
- = ppCat [ppPStr SLIT("Could not find original interface for:"), ppPStr mod]
+------------------------
+checkEntityUsage new_vers (name,old_vers)
+ = case lookupNameEnv new_vers name of
-noDeclInIfaceErr mod str sty
- = ppBesides [ppPStr SLIT("Could not find interface declaration of: "),
- ppPStr mod, ppStr ".", ppPStr str]
+ Nothing -> -- We used it before, but it ain't there now
+ out_of_date (sep [ptext SLIT("No longer exported:"), ppr name])
-cannaeReadErr file err sty
- = ppBesides [ppPStr SLIT("Failed in reading file: "), ppStr file, ppStr "; error=", ppStr (show err)]
+ Just new_vers -- It's there, but is it up to date?
+ | new_vers == old_vers -> returnRn upToDate
+ | otherwise -> out_of_date (sep [ptext SLIT("Out of date:"), ppr name])
+
+up_to_date msg = traceHiDiffsRn msg `thenRn_` returnRn upToDate
+out_of_date msg = traceHiDiffsRn msg `thenRn_` returnRn outOfDate
+\end{code}
-ifaceLookupWiredErr msg n sty
- = ppBesides [ppPStr SLIT("Why am I looking up a wired-in "), ppStr msg, ppChar ':', ppr sty n]
-badIfaceLookupErr msg name decl sty
- = ppBesides [ppPStr SLIT("Expected a "), ppStr msg, ppStr " declaration, but got this: ???"]
+%*********************************************************
+%* *
+\subsection{Errors}
+%* *
+%*********************************************************
-ifaceIoErr io_msg rn sty
- = ppBesides [io_msg sty, ppStr "; looking for: ", ppr sty rn]
+\begin{code}
+getDeclErr name
+ = vcat [ptext SLIT("Failed to find interface decl for") <+> quotes (ppr name),
+ ptext SLIT("from module") <+> quotes (ppr (nameModule name))
+ ]
\end{code}