X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Frename%2FRnIfaces.lhs;h=a56da3b240449171dee2e7471161d1c2596c8657;hb=bac531aaf56c7558eda70531e9565f753d21f848;hp=f805e312e9b6cb720dec3bc3615a400db068992e;hpb=573ef10b2afd99d3c6a36370a9367609716c97d2;p=ghc-hetmet.git diff --git a/ghc/compiler/rename/RnIfaces.lhs b/ghc/compiler/rename/RnIfaces.lhs index f805e31..a56da3b 100644 --- a/ghc/compiler/rename/RnIfaces.lhs +++ b/ghc/compiler/rename/RnIfaces.lhs @@ -1,872 +1,936 @@ % -% (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 ( DynFlags, opt_NoPruneDecls, opt_NoPruneTyDecls, opt_IgnoreIfacePragmas ) +import HscTypes +import HsSyn ( HsDecl(..), Sig(..), TyClDecl(..), ConDecl(..), ConDetails(..), + InstDecl(..), HsType(..), hsTyVarNames, getBangType ) -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-} ) -\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 - -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) +import HsImpExp ( ImportDecl(..) ) +import RdrHsSyn ( RdrNameHsDecl, RdrNameTyClDecl, RdrNameInstDecl ) +import RnHsSyn ( RenamedHsDecl, extractHsTyNames, extractHsCtxtTyNames, tyClDeclFVs ) +import RnHiFiles ( tryLoadInterface, loadHomeInterface, loadInterface, + loadOrphanModules + ) +import RnSource ( rnTyClDecl, rnDecl ) +import RnEnv +import RnMonad +import Id ( idType ) +import Type ( namesOfType ) +import TyCon ( isSynTyCon, getSynTyConDefn ) +import Name ( Name {-instance NamedThing-}, nameOccName, + nameModule, isLocallyDefined, nameUnique, + NamedThing(..), + elemNameEnv + ) +import Module ( Module, ModuleEnv, + moduleName, isModuleInThisPackage, + ModuleName, WhereFrom(..), + emptyModuleEnv, lookupModuleEnvByName, + extendModuleEnv_C, lookupWithDefaultModuleEnv + ) +import NameSet +import PrelInfo ( wiredInThingEnv, fractionalClassKeys ) +import TysWiredIn ( doubleTyCon ) +import Maybes ( orElse ) +import FiniteMap +import Outputable +import Bag + +import List ( nub ) \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). -Note: we have two notions of interface - * the interface for a particular file name - * the (combined) interface for a particular module name +%********************************************************* +%* * +\subsection{Getting what a module exports} +%* * +%********************************************************* -The idea is that two source files may declare a module -with the same name with the declarations being merged. +@getInterfaceExports@ is called only for directly-imported modules. -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} +getInterfaceExports :: ModuleName -> WhereFrom -> RnMG (Module, [(ModuleName,Avails)]) +getInterfaceExports mod_name from + = getHomeIfaceTableRn `thenRn` \ hit -> + case lookupModuleEnvByName hit mod_name of { + Just mi -> returnRn (mi_module mi, mi_exports mi) ; + Nothing -> + + loadInterface doc_str mod_name from `thenRn` \ ifaces -> + case lookupModuleEnvByName (iPIT ifaces) mod_name of + Just mi -> returnRn (mi_module mi, mi_exports mi) ; + -- loadInterface always puts something in the map + -- even if it's a fake + Nothing -> pprPanic "getInterfaceExports" (ppr mod_name) + } + where + doc_str = sep [ppr mod_name, ptext SLIT("is directly imported")] +\end{code} -ToDo: Check duplicate definitons are the same. -ToDo: Check/Merge duplicate pragmas. +%********************************************************* +%* * +\subsection{Instance declarations are handled specially} +%* * +%********************************************************* \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 +getImportedInstDecls :: NameSet -> RnMG [(Module,RdrNameHsDecl)] +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 - b_env = if class_or_tycon then b_tc_names else b_val_names + orphan_mods = + [mod | (mod, (True, _, False)) <- fmToList (iImpModInfo ifaces)] 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 -> + 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 -> let - return_maybe_decl = return maybe_decl - return_failed msg = return (CachingFail msg) + (decls, new_insts) = selectGated gates (iInsts ifaces) 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 _ -> pprPanic "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) + setIfacesRn (ifaces { iInsts = new_insts }) `thenRn_` + + 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 - 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 + gate_list = nameSetToList gates + +ppr_brief_inst_decl (mod, InstD (InstDecl inst_ty _ _ _ _)) + = case inst_ty of + HsForAllTy _ _ tau -> ppr tau + other -> ppr inst_ty + +getImportedRules :: RnMG [(Module,RdrNameHsDecl)] +getImportedRules + | opt_IgnoreIfacePragmas = returnRn [] + | otherwise + = getIfacesRn `thenRn` \ ifaces -> + let + gates = iSlurp ifaces -- Anything at all that's been slurped + rules = iRules ifaces + (decls, new_rules) = selectGated gates rules + in + 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 decl_bag + -- Select only those decls whose gates are *all* in 'gates' +#ifdef DEBUG + | opt_NoPruneDecls -- Just to try the effect of not gating at all + = (foldrBag (\ (_,d) ds -> d:ds) [] decl_bag, emptyBag) -- Grab them all + + | otherwise +#endif + = foldrBag select ([], emptyBag) decl_bag + where + select (reqd, decl) (yes, no) + | isEmptyNameSet (reqd `minusNameSet` gates) = (decl:yes, no) + | otherwise = (yes, (reqd,decl) `consBag` no) \end{code} + +%********************************************************* +%* * +\subsection{Keeping track of what we've slurped, and version numbers} +%* * +%********************************************************* + +getImportVersions 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. It records: + +\begin{itemize} +\item (a) anything reachable from its body code +\item (b) any module exported with a @module Foo@ +\item (c) anything reachable from an exported item +\end{itemize} + +Why (b)? Because if @Foo@ changes then this module's export list +will change, so we must recompile this module at least as far as +making a new interface file --- but in practice that means complete +recompilation. + +Why (c)? Consider this: +\begin{verbatim} + module A( f, g ) where | module B( f ) where + import B( f ) | f = h 3 + g = ... | h = ... +\end{verbatim} + +Here, @B.f@ isn't used in A. Should we nevertheless record @B.f@ in +@A@'s usages? Our idea is that we aren't going to touch A.hi if it is +*identical* to what it was before. If anything about @B.f@ changes +than anyone who imports @A@ should be recompiled in case they use +@B.f@ (they'll get an early exit if they don't). So, if anything +about @B.f@ changes we'd better make sure that something in A.hi +changes, and the convenient way to do that is to record the version +number @B.f@ in A.hi in the usage list. If B.f changes that'll force a +complete recompiation of A, which is overkill but it's the only way to +write a new, slightly different, A.hi. + +But the example is tricker. Even if @B.f@ doesn't change at all, +@B.h@ may do so, and this change may not be reflected in @f@'s version +number. But with -O, a module that imports A must be recompiled if +@B.h@ changes! So A must record a dependency on @B.h@. So we treat +the occurrence of @B.f@ in the export list *just as if* it were in the +code of A, and thereby haul in all the stuff reachable from it. + +[NB: If B was compiled with -O, but A isn't, we should really *still* +haul in all the unfoldings for B, in case the module that imports A *is* +compiled with -O. I think this is the case.] + +Even if B is used at all we get a usage line for B + import B :: ... ; +in A.hi, to record the fact that A does import B. 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. + \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) - ) - 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 +mkImportInfo :: ModuleName -- Name of this module + -> [ImportDecl n] -- The import decls + -> RnMG [ImportVersion Name] + +mkImportInfo this_mod imports + = getIfacesRn `thenRn` \ ifaces -> + getHomeIfaceTableRn `thenRn` \ hit -> + let + import_all_mods :: [ModuleName] + -- Modules where we imported all the names + -- (apart from hiding some, perhaps) + import_all_mods = nub [ m | ImportDecl m _ _ _ imp_list _ <- imports, + import_all imp_list ] + + import_all (Just (False, _)) = False -- Imports are specified explicitly + import_all other = True -- Everything is imported + + mod_map = iImpModInfo ifaces + imp_names = iVSlurp ifaces + pit = iPIT ifaces + + -- mv_map groups together all the things imported from a particular module. + mv_map :: ModuleEnv [Name] + mv_map = foldr add_mv emptyModuleEnv imp_names + + add_mv name mv_map = addItem mv_map (nameModule name) name + + -- Build the result list by adding info for each module. + -- For (a) a library module, we don't record it at all unless it contains orphans + -- (We must never lose track of orphans.) + -- + -- (b) a source-imported module, don't record the dependency at all + -- + -- (b) may seem a bit strange. The idea is that the usages in a .hi file records + -- *all* the module's dependencies other than the loop-breakers. We use + -- this info in findAndReadInterface to decide whether to look for a .hi file or + -- a .hi-boot file. + -- + -- This means we won't track version changes, or orphans, from .hi-boot files. + -- The former is potentially rather bad news. It could be fixed by recording + -- whether something is a boot file along with the usage info for it, but + -- I can't be bothered just now. + + mk_imp_info mod_name (has_orphans, is_boot, opened) so_far + | mod_name == this_mod -- Check if M appears in the set of modules 'below' M + -- This seems like a convenient place to check + = WARN( not is_boot, ptext SLIT("Wierd:") <+> ppr this_mod <+> + ptext SLIT("imports itself (perhaps indirectly)") ) + so_far + + | not opened -- We didn't even open the interface + = -- 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 + -- information. The Nothing says that we didn't even open the interface + -- file but we must still propagate the dependency info. + -- The module in question must be a local module (in the same package) + go_for_it NothingAtAll + + + | is_lib_module && not has_orphans + = so_far + + | is_lib_module -- Record the module version only + = go_for_it (Everything module_vers) + + | otherwise + = go_for_it whats_imported + + where + go_for_it exports = (mod_name, has_orphans, is_boot, exports) : so_far + mod_iface = lookupTableByModName hit pit mod_name `orElse` panic "mkImportInfo" + mod = mi_module mod_iface + is_lib_module = not (isModuleInThisPackage mod) + version_info = mi_version mod_iface + version_env = vers_decls version_info + module_vers = vers_module version_info + + whats_imported = Specifically module_vers + export_vers import_items + (vers_rules version_info) + + import_items = [(n,v) | n <- lookupWithDefaultModuleEnv mv_map [] mod, + let v = lookupNameEnv version_env n `orElse` + pprPanic "mk_whats_imported" (ppr n) + ] + export_vers | moduleName mod `elem` import_all_mods + = Just (vers_exports version_info) + | otherwise + = Nothing + + import_info = foldFM mk_imp_info [] mod_map + in + traceRn (text "Modules in Ifaces: " <+> fsep (map ppr (keysFM mod_map))) `thenRn_` + returnRn import_info + + +addItem :: ModuleEnv [a] -> Module -> a -> ModuleEnv [a] +addItem fm mod x = extendModuleEnv_C add_item fm mod [x] + where + add_item xs _ = x:xs \end{code} +%********************************************************* +%* * +\subsection{Slurping declarations} +%* * +%********************************************************* \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) - 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 +------------------------------------------------------- +slurpImpDecls source_fvs + = traceRn (text "slurpImp" <+> fsep (map ppr (nameSetToList source_fvs))) `thenRn_` - 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) -> + -- The current slurped-set records all local things + getSlurped `thenRn` \ source_binders -> + slurpSourceRefs source_binders source_fvs `thenRn` \ (decls, needed) -> --- ASSERT(isEmptyBag occ_dups) --- False because we may get a dup on the name we just shoved in + -- Then get everything else + closeDecls decls needed `thenRn` \ decls1 -> - (new_def_env, new_occ_env, us) }} + -- Finally, get any deferred data type decls + slurpDeferredDecls decls1 `thenRn` \ final_decls -> ----------------- -type To_Return = (([RenamedTyDecl], [RenamedClassDecl], [RenamedInstDecl], [RenamedSig]), - ImplicitEnv, -- new names used implicitly - (Bag Error, Bag Warning) - ) + returnRn final_decls -empty_return :: To_Return -empty_return = (([],[],[],[]), emptyImplicitEnv, (emptyBag,emptyBag)) -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) +------------------------------------------------------- +slurpSourceRefs :: NameSet -- Variables defined in source + -> FreeVars -- Variables referenced in source + -> RnMG ([RenamedHsDecl], + FreeVars) -- Un-satisfied needs +-- The declaration (and hence home module) of each gate has +-- already been loaded -add_insts is ((tydecls, classdecls, instdecls, sigs), implicit, msgs) - = ((tydecls, classdecls, is ++ instdecls, sigs), implicit, msgs) +slurpSourceRefs source_binders source_fvs + = go_outer [] -- Accumulating decls + emptyFVs -- Unsatisfied needs + emptyFVs -- Accumulating gates + (nameSetToList source_fvs) -- Things whose defn hasn't been loaded yet + where + -- The outer loop repeatedly slurps the decls for the current gates + -- and the instance decls + + -- The outer loop is needed because consider + -- instance Foo a => Baz (Maybe a) where ... + -- It may be that @Baz@ and @Maybe@ are used in the source module, + -- but not @Foo@; so we need to chase @Foo@ too. + -- + -- We also need to follow superclass refs. In particular, 'chasing @Foo@' must + -- include actually getting in Foo's class decl + -- class Wib a => Foo a where .. + -- so that its superclasses are discovered. The point is that Wib is a gate too. + -- We do this for tycons too, so that we look through type synonyms. + + 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 -> + rnInstDecls 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) + WiredIn -> returnRn (decls, fvs, gates `plusFV` getWiredInGates wanted_name) + Deferred -> returnRn (decls, fvs, gates `addOneFV` wanted_name) -- It's a type constructor + + HereItIs decl -> rnIfaceTyClDecl decl `thenRn` \ (new_decl, fvs1) -> + returnRn (TyClD new_decl : decls, + fvs1 `plusFV` fvs, + gates `plusFV` getGates source_fvs new_decl) + +rnInstDecls decls fvs gates [] + = returnRn (decls, fvs, gates) +rnInstDecls decls fvs gates (d:ds) + = rnIfaceDecl d `thenRn` \ (new_decl, fvs1) -> + rnInstDecls (new_decl:decls) + (fvs1 `plusFV` fvs) + (gates `plusFV` getInstDeclGates new_decl) + ds +\end{code} -add_implicits (val_imps, tc_imps) (decls, (val_fm, tc_fm), msgs) - = (decls, (val_fm `plusFM` val_imps, tc_fm `plusFM` tc_imps), msgs) -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)) +\begin{code} +------------------------------------------------------- +-- 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 decls emptyFVs rule_decls `thenRn` \ (decls1, needed1) -> + closeDecls decls1 needed1 + + +------------------------------------------------------- +-- 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 + 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 :: [RenamedHsDecl] -> FreeVars + -> [(Module, RdrNameHsDecl)] + -> RnM d ([RenamedHsDecl], FreeVars) +rnIfaceDecls decls fvs [] = returnRn (decls, fvs) +rnIfaceDecls decls fvs (d:ds) = rnIfaceDecl d `thenRn` \ (new_decl, fvs1) -> + rnIfaceDecls (new_decl:decls) (fvs1 `plusFV` fvs) ds + +rnIfaceDecl (mod, decl) = initIfaceRnMS mod (rnDecl decl) +rnIfaceTyClDecl (mod, decl) = initIfaceRnMS mod (rnTyClDecl decl) `thenRn` \ decl' -> + returnRn (decl', tyClDeclFVs decl') \end{code} + \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 +getSlurped + = getIfacesRn `thenRn` \ ifaces -> + returnRn (iSlurp ifaces) + +recordSlurp ifaces@(Ifaces { iSlurp = slurped_names, iVSlurp = imp_names }) + avail + = let + new_slurped_names = addAvailToNameSet slurped_names avail + new_imp_names = availName avail : imp_names in - returnRn (AddedTy rn_decl, defds, implicits) + ifaces { iSlurp = new_slurped_names, iVSlurp = new_imp_names } -rnIfaceDecl (NewTypeSig tc dc _ decl) - = rnTyDecl decl `thenRn` \ rn_decl -> - lookupTyCon tc `thenRn` \ rn_tc -> - lookupValue dc `thenRn` \ rn_dc -> - getImplicitUpRn `thenRn` \ mentioned -> +recordLocalSlurps local_avails + = getIfacesRn `thenRn` \ ifaces -> let - defds = ([(dc, rn_dc)], [(tc, rn_tc)]) - implicits = mentioned `sub` defds + new_slurped_names = foldl addAvailToNameSet (iSlurp ifaces) local_avails 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 -> - let - defds = (zip dcs rn_dcs ++ zip fcs rn_fcs , [(tc, rn_tc)]) - implicits = mentioned `sub` defds - in - returnRn (AddedTy rn_decl, defds, implicits) + setIfacesRn (ifaces { iSlurp = new_slurped_names }) +\end{code} -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 -> - let - defds = (ops `zip` rn_ops, [(clas, rn_clas)]) - implicits = mentioned `sub` defds - 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 - in - returnRn (AddedSig (Sig rn_f rn_ty noGenPragmas src_loc), defds, implicits) ----- -sub :: ImplicitEnv -> ([(RdrName,RnName)], [(RdrName,RnName)]) -> ImplicitEnv -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)) -\end{code} +%********************************************************* +%* * +\subsection{Deferred declarations} +%* * +%********************************************************* + +The idea of deferred declarations is this. Suppose we have a function + f :: T -> Int + data T = T1 A | T2 B + data A = A1 X | A2 Y + data B = B1 P | B2 Q +Then we don't want to load T and all its constructors, and all +the types those constructors refer to, and all the types *those* +constructors refer to, and so on. That might mean loading many more +interface files than is really necessary. So we 'defer' loading T. -% ------------------------------ +But f might be strict, and the calling convention for evaluating +values of type T depends on how many constructors T has, so +we do need to load T, but not the full details of the type T. +So we load the full decl for T, but only skeleton decls for A and B: + f :: T -> Int + data T = {- 2 constructors -} -@cacheInstModules@: cache instance modules specified in imports +Whether all this is worth it is moot. \begin{code} -cacheInstModules :: IfaceCache -> [Module] -> IO (Bag Error) +slurpDeferredDecls :: [RenamedHsDecl] -> RnMG [RenamedHsDecl] +slurpDeferredDecls decls = returnRn decls + +{- OMIT FOR NOW +slurpDeferredDecls :: [RenamedHsDecl] -> RnMG [RenamedHsDecl] +slurpDeferredDecls decls + = getDeferredDecls `thenRn` \ def_decls -> + rnIfaceDecls decls emptyFVs (map stripDecl def_decls) `thenRn` \ (decls1, fvs) -> + ASSERT( isEmptyFVs fvs ) + returnRn decls1 + +stripDecl (mod, TyClD (TyData dt _ tc tvs _ nconstrs _ loc name1 name2)) + = (mod, TyClD (TyData dt [] tc tvs [] nconstrs Nothing loc + name1 name2)) + -- Nuke the context and constructors + -- But retain the *number* of constructors! + -- Also the tvs will have kinds on them. +-} +\end{code} -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 -> - -- Sanity Check: - -- Assert that instance modules given by direct imports contains - -- instance modules extracted from all visited modules +%********************************************************* +%* * +\subsection{Extracting the `gates'} +%* * +%********************************************************* - readVar iface_var ST_THEN \ (all_iface_fm, _, _) -> - let - all_ifaces = eltsFM all_iface_fm - (all_imods, _) = removeDups cmpPString (bagToList (unionManyBags (map get_ims (all_ifaces)))) - in - ASSERT(sortLt (<) imp_imods == sortLt (<) all_imods) +When we import a declaration like +\begin{verbatim} + data T = T1 Wibble | T2 Wobble +\end{verbatim} +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. + +@getGates@ takes a newly imported (and renamed) decl, and the free +vars of the source program, and extracts from the decl the gate names. - return (bag_errs err_or_ifaces) +\begin{code} +getGates source_fvs (IfaceSig _ ty _ _) + = extractHsTyNames ty + +getGates source_fvs (ClassDecl ctxt cls tvs _ sigs _ _ _ ) + = (delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) sigs) + (hsTyVarNames tvs) + `addOneToNameSet` cls) + `plusFV` maybe_double where - bag_errs [] = emptyBag - bag_errs (Failed err :rest) = err `consBag` bag_errs rest - bag_errs (Succeeded _:rest) = bag_errs rest + get (ClassOpSig n _ ty _) + | n `elemNameSet` source_fvs = 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 + +getGates source_fvs (TySynonym tycon tvs ty _) + = delListFromNameSet (extractHsTyNames ty) + (hsTyVarNames tvs) + -- A type synonym type constructor isn't a "gate" for instance decls + +getGates source_fvs (TyData _ ctxt tycon tvs cons _ _ _ _ _) + = delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) cons) + (hsTyVarNames tvs) + `addOneToNameSet` tycon + where + get (ConDecl n _ tvs ctxt details _) + | n `elemNameSet` source_fvs + -- 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 (`elemNameSet` source_fvs) fs = get_bang t + | otherwise = emptyFVs + + get_bang bty = extractHsTyNames (getBangType bty) \end{code} +@getWiredInGates@ is just like @getGates@, but it sees a wired-in @Name@ +rather than a declaration. + +\begin{code} +getWiredInGates :: Name -> FreeVars +getWiredInGates name -- No classes are wired in + = case lookupNameEnv wiredInThingEnv name of + Just (AnId the_id) -> getWiredInGates_s (namesOfType (idType the_id)) + + Just (ATyCon tc) + | isSynTyCon tc + -> getWiredInGates_s (delListFromNameSet (namesOfType ty) (map getName tyvars)) + where + (tyvars,ty) = getSynTyConDefn tc + + other -> unitFV name -@rnIfaceInstStuff@: Deal with instance declarations from interface files. +getWiredInGates_s names = foldr (plusFV . getWiredInGates) emptyFVs (nameSetToList names) +\end{code} \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 +getInstDeclGates (InstD (InstDecl inst_ty _ _ _ _)) = extractHsTyNames inst_ty +getInstDeclGates other = emptyFVs +\end{code} - -- Sanity Check: - -- Assert that there are no more instances for the done instances - claim_done = filter is_done_inst all_insts - claim_done_env = foldr add_done_inst emptyFM claim_done +%********************************************************* +%* * +\subsection{Getting in a declaration} +%* * +%********************************************************* - 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)) - } +\begin{code} +importDecl :: Name -> RnMG ImportDeclResult + +data ImportDeclResult + = AlreadySlurped + | WiredIn + | Deferred + | HereItIs (Module, RdrNameTyClDecl) + +importDecl name + = -- Check if it was loaded before beginning this module + checkAlreadyAvailable name `thenRn` \ done -> + if done then + returnRn AlreadySlurped + else + + -- Check if we slurped it in while compiling this module + getIfacesRn `thenRn` \ ifaces -> + if name `elemNameSet` iSlurp ifaces then + returnRn AlreadySlurped + else + + -- Don't slurp in decls from this module's own interface file + -- (Indeed, this shouldn't happen.) + if isLocallyDefined name then + addWarnRn (importDeclWarn name) `thenRn_` + returnRn AlreadySlurped + else + + -- When we find a wired-in name we must load its home + -- module so that we find any instance decls lurking therein + if name `elemNameEnv` wiredInThingEnv then + loadHomeInterface doc name `thenRn_` + returnRn WiredIn + + else getNonWiredInDecl name + where + doc = ptext SLIT("need home module for wired in thing") <+> ppr name + +getNonWiredInDecl :: Name -> RnMG ImportDeclResult +getNonWiredInDecl needed_name + = traceRn doc_str `thenRn_` + loadHomeInterface doc_str needed_name `thenRn` \ ifaces -> + case lookupNameEnv (iDecls ifaces) needed_name of + +{- OMIT DEFERRED STUFF FOR NOW, TILL GHCI WORKS + Just (version, avail, is_tycon_name, decl@(_, TyClD (TyData DataType _ _ _ _ ncons _ _ _ _))) + -- This case deals with deferred import of algebraic data types + + | not opt_NoPruneTyDecls + + && (opt_IgnoreIfacePragmas || ncons > 1) + -- We only defer if imported interface pragmas are ingored + -- or if it's not a product type. + -- Sole reason: The wrapper for a strict function may need to look + -- inside its arg, and hence need to see its arg type's constructors. + + && not (getUnique tycon_name `elem` cCallishTyKeys) + -- Never defer ccall types; we have to unbox them, + -- and importing them does no harm + + + -> -- OK, so we're importing a deferrable data type + if needed_name == tycon_name + -- The needed_name is the TyCon of a data type decl + -- Record that it's slurped, put it in the deferred set + -- and don't return a declaration at all + setIfacesRn (recordSlurp (ifaces {iDeferred = iDeferred ifaces + `addOneToNameSet` tycon_name}) + version (AvailTC needed_name [needed_name])) `thenRn_` + returnRn Deferred + + else + -- The needed name is a constructor of a data type decl, + -- getting a constructor, so remove the TyCon from the deferred set + -- (if it's there) and return the full declaration + setIfacesRn (recordSlurp (ifaces {iDeferred = iDeferred ifaces + `delFromNameSet` tycon_name}) + version avail) `thenRn_` + returnRn (HereItIs decl) + where + tycon_name = availName avail +-} + + Just (avail,_,decl) + -> setIfacesRn (recordSlurp ifaces avail) `thenRn_` + returnRn (HereItIs decl) + + Nothing + -> addErrRn (getDeclErr needed_name) `thenRn_` + returnRn AlreadySlurped 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) + doc_str = ptext SLIT("need decl for") <+> ppr needed_name + +{- OMIT FOR NOW +getDeferredDecls :: RnMG [(Module, RdrNameHsDecl)] +getDeferredDecls + = getIfacesRn `thenRn` \ ifaces -> + let + decls_map = iDecls ifaces + deferred_names = nameSetToList (iDeferred ifaces) + get_abstract_decl n = case lookupNameEnv decls_map n of + Just (_, _, _, decl) -> decl + in + traceRn (sep [text "getDeferredDecls", nest 4 (fsep (map ppr deferred_names))]) `thenRn_` + returnRn (map get_abstract_decl deferred_names) +-} \end{code} +@getWiredInDecl@ maps a wired-in @Name@ to what it makes available. +It behaves exactly as if the wired in decl were actually in an interface file. +Specifically, +\begin{itemize} +\item if the wired-in name is a data type constructor or a data constructor, + it brings in the type constructor and all the data constructors; and + marks as ``occurrences'' any free vars of the data con. + +\item similarly for synonum type constructor + +\item if the wired-in name is another wired-in Id, it marks as ``occurrences'' + the free vars of the Id's type. + +\item it loads the interface file for the wired-in thing for the + sole purpose of making sure that its instance declarations are available +\end{itemize} +All this is necessary so that we know all types that are ``in play'', so +that we know just what instances to bring into scope. + + +%******************************************************** +%* * +\subsection{Checking usage information} +%* * +%******************************************************** + +@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. + \begin{code} -rnIfaceInst :: (Module, RdrIfaceInst) -> RnM_Fixes REAL_WORLD RenamedInstDecl +type RecompileRequired = Bool +upToDate = False -- Recompile not required +outOfDate = True -- Recompile required + +recompileRequired :: Module + -> Bool -- Source unchanged + -> Maybe ModIface -- Old interface, if any + -> RnMG RecompileRequired +recompileRequired mod source_unchanged maybe_iface + = traceRn (text "Considering whether compilation is required for" <+> ppr mod <> colon) `thenRn_` + + -- CHECK WHETHER THE SOURCE HAS CHANGED + if not source_unchanged then + traceRn (nest 4 (text "Source file changed or recompilation check turned off")) `thenRn_` + returnRn outOfDate + else -rnIfaceInst (imod, InstSig _ _ _ inst_decl) = rnInstDecl (inst_decl imod) + -- CHECK WHETHER WE HAVE AN OLD IFACE + case maybe_iface of + Nothing -> traceRn (nest 4 (ptext SLIT("No old interface file"))) `thenRn_` + returnRn outOfDate ; + + Just iface -> -- Source code unchanged and no errors yet... carry on + checkList [checkModUsage u | u <- mi_usages iface] + +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} -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, _) -> +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, _, _, whats_imported) + = tryLoadInterface doc_str mod_name ImportBySystem `thenRn` \ (ifaces, maybe_err) -> + 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 + + Nothing -> + + getHomeIfaceTableRn `thenRn` \ hit -> let - all_ifaces = eltsFM orig_iface_fm - -- all the interfaces we have looked at + mod_details = lookupTableByModName hit (iPIT ifaces) mod_name + `orElse` panic "checkModUsage" + new_vers = mi_version mod_details + 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, []) + -- 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 + + -- 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.")) + + }} 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 + doc_str = sep [ptext SLIT("need version info for"), ppr mod_name] -\end{code} +------------------------ +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")) -\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.")] +------------------------ +checkExportList Nothing new_vers = upToDate +checkExportList (Just v) new_vers = v /= vers_exports new_vers -noIfaceErr mod sty - = ppCat [ppPStr SLIT("Could not find interface for:"), ppPStr mod] +------------------------ +checkEntityUsage new_vers (name,old_vers) + = case lookupNameEnv new_vers name of -noOrigIfaceErr mod sty - = ppCat [ppPStr SLIT("Could not find original interface for:"), ppPStr mod] + Nothing -> -- We used it before, but it ain't there now + out_of_date (sep [ptext SLIT("No longer exported:"), ppr name]) -noDeclInIfaceErr mod str sty - = ppBesides [ppPStr SLIT("Could not find interface declaration of: "), - ppPStr mod, ppStr ".", ppPStr str] + 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]) -cannaeReadErr file err sty - = ppBesides [ppPStr SLIT("Failed in reading file: "), ppStr file, ppStr "; error=", ppStr (show err)] +up_to_date msg = traceRn msg `thenRn_` returnRn upToDate +out_of_date msg = traceRn 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)) + ] + +importDeclWarn name + = sep [ptext SLIT( + "Compiler tried to import decl from interface file with same name as module."), + ptext SLIT( + "(possible cause: module name clashes with interface file already in scope.)") + ] $$ + hsep [ptext SLIT("name:"), quotes (ppr name)] \end{code}