+checkSlurped name
+ = getIfacesRn `thenRn` \ (Ifaces _ _ _ _ slurped_names _ _ _) ->
+ returnRn (name `elemNameSet` slurped_names)
+
+recordSlurp maybe_version avail
+ = -- traceRn (ppSep [ppStr "Record slurp:", pprAvail PprDebug avail]) `thenRn_`
+ getIfacesRn `thenRn` \ ifaces ->
+ let
+ Ifaces this_mod mod_vers export_envs decls slurped_names imp_names insts inst_mods = ifaces
+ new_slurped_names = addAvailToNameSet slurped_names avail
+
+ new_imp_names = case maybe_version of
+ Just version -> (availName avail, version) : imp_names
+ Nothing -> imp_names
+
+ new_ifaces = Ifaces this_mod mod_vers export_envs decls
+ new_slurped_names
+ new_imp_names
+ insts
+ inst_mods
+ in
+ setIfacesRn new_ifaces
+\end{code}
+
+%*********************************************************
+%* *
+\subsection{Getting other stuff}
+%* *
+%*********************************************************
+
+\begin{code}
+getInterfaceExports :: Module -> RnMG (Avails, [(OccName,Fixity)])
+getInterfaceExports mod
+ = loadInterface doc_str mod `thenRn` \ (Ifaces _ _ export_envs _ _ _ _ _) ->
+ case lookupFM export_envs mod of
+ Nothing -> -- Not there; it must be that the interface file wasn't found;
+ -- the error will have been reported already.
+ -- (Actually loadInterface should put the empty export env in there
+ -- anyway, but this does no harm.)
+ returnRn ([],[])
+
+ Just stuff -> returnRn stuff
+ where
+ doc_str = ppSep [pprModule PprDebug mod, ppPStr SLIT("is directly imported")]
+
+
+getImportedInstDecls :: RnMG [(Module,RdrNameInstDecl)]
+getImportedInstDecls
+ = -- First load any special-instance modules that aren't aready loaded
+ getSpecialInstModules `thenRn` \ inst_mods ->
+ mapRn load_it inst_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
+ Ifaces this_mod mod_vers export_envs decls slurped_names imp_names insts inst_mods = ifaces
+
+ -- An instance decl is ungated if all its gates have been slurped
+ select_ungated :: IfaceInst -- A gated inst decl
+
+ -> ([(Module, RdrNameInstDecl)], [IfaceInst]) -- Accumulator
+
+ -> ([(Module, RdrNameInstDecl)], -- The ungated ones
+ [IfaceInst]) -- Still gated, but with
+ -- depeleted gates
+ select_ungated (decl,gates) (ungated_decls, gated_decls)
+ | null remaining_gates
+ = (decl : ungated_decls, gated_decls)
+ | otherwise
+ = (ungated_decls, (decl, remaining_gates) : gated_decls)
+ where
+ remaining_gates = filter (not . (`elemNameSet` slurped_names)) gates
+
+ (un_gated_insts, still_gated_insts) = foldrBag select_ungated ([], []) insts
+
+ new_ifaces = Ifaces this_mod mod_vers export_envs decls slurped_names imp_names
+ (listToBag still_gated_insts)
+ inst_mods
+ in
+ setIfacesRn new_ifaces `thenRn_`
+ returnRn un_gated_insts
+ where
+ load_it mod = loadInterface (doc_str mod) mod
+ doc_str mod = ppSep [pprModule PprDebug mod, ppPStr SLIT("is a special-instance module")]
+
+
+getSpecialInstModules :: RnMG [Module]
+getSpecialInstModules
+ = getIfacesRn `thenRn` \ ifaces ->
+ let
+ Ifaces _ _ _ _ _ _ _ inst_mods = ifaces
+ in
+ returnRn inst_mods
+\end{code}
+
+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:
+ - anything reachable from its body code
+ - any module exported with a "module Foo".
+
+Why the latter? 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.
+
+What about this?
+ module A( f, g ) where module B( f ) where
+ import B( f ) f = h 3
+ g = ... h = ...
+
+Should we record B.f in A's usages? In fact we don't. Certainly, if
+anything about B.f changes than anyone who imports A should be recompiled;
+they'll get an early exit if they don't use B.f. However, 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. So there are two things going on when compiling module A:
+
+1. Are A.o and A.hi correct? Then we can bale out early.
+2. Should modules that import A be recompiled?
+
+For (1) it is slightly harmful to record B.f in A's usages, because a change in
+B.f's version will provoke full recompilation of A, producing an identical A.o,
+and A.hi differing only in its usage-version of B.f (which isn't used by any importer).
+
+For (2), because of the tricky B.h question above, we ensure that A.hi is touched
+(even if identical to its previous version) if A's recompilation was triggered by
+an imported .hi file date change. Given that, there's no need to record B.f in
+A's usages.
+
+On the other hand, if A exports "module B" then we *do* count module B among
+A's usages, because we must recompile A to ensure that A.hi changes appropriately.
+
+\begin{code}
+getImportVersions :: Module -- Name of this module
+ -> Maybe [IE any] -- Export list for this module
+ -> RnMG (VersionInfo Name) -- Version info for these names
+
+getImportVersions this_mod exports
+ = getIfacesRn `thenRn` \ ifaces ->
+ let
+ Ifaces _ mod_versions_map _ _ _ imp_names _ _ = ifaces
+ mod_version mod = expectJust "import_versions" (lookupFM mod_versions_map mod)
+
+ -- mv_map groups together all the things imported from a particular module.
+ mv_map, mv_map_mod :: FiniteMap Module [LocalVersion Name]
+
+ mv_map_mod = foldl add_mod emptyFM export_mods
+ -- mv_map_mod records all the modules that have a "module M"
+ -- in this module's export list
+
+ mv_map = foldl add_mv mv_map_mod imp_names
+ -- mv_map adds the version numbers of things exported individually
+ in
+ returnRn [ (mod, mod_version mod, local_versions)
+ | (mod, local_versions) <- fmToList mv_map
+ ]
+
+ where
+ export_mods = case exports of
+ Nothing -> []
+ Just es -> [mod | IEModuleContents mod <- es, mod /= this_mod]
+
+ add_mv mv_map v@(name, version)
+ = addToFM_C (\ ls _ -> (v:ls)) mv_map mod [v]
+ where
+ (mod,_) = modAndOcc name
+
+ add_mod mv_map mod = addToFM mv_map mod []
+\end{code}
+
+%*********************************************************
+%* *
+\subsection{Getting binders out of a declaration}
+%* *
+%*********************************************************
+
+@getDeclBinders@ returns the names for a @RdrNameHsDecl@.
+It's used for both source code (from @availsFromDecl@) and interface files
+(from @loadDecl@).
+
+It doesn't deal with source-code specific things: ValD, DefD. They
+are handled by the sourc-code specific stuff in RnNames.
+
+\begin{code}
+getDeclBinders :: (RdrName -> SrcLoc -> RnMG Name) -- New-name function
+ -> RdrNameHsDecl
+ -> RnMG AvailInfo
+
+getDeclBinders new_name (TyD (TyData _ tycon _ condecls _ _ src_loc))
+ = new_name tycon src_loc `thenRn` \ tycon_name ->
+ getConFieldNames new_name condecls `thenRn` \ sub_names ->
+ returnRn (AvailTC tycon_name (tycon_name : sub_names))
+
+getDeclBinders new_name (TyD (TyNew _ tycon _ (NewConDecl con _ con_loc) _ _ src_loc))
+ = new_name tycon src_loc `thenRn` \ tycon_name ->
+ new_name con src_loc `thenRn` \ con_name ->
+ returnRn (AvailTC tycon_name [tycon_name, con_name])
+
+getDeclBinders new_name (TyD (TySynonym tycon _ _ src_loc))
+ = new_name tycon src_loc `thenRn` \ tycon_name ->
+ returnRn (Avail tycon_name)
+
+getDeclBinders new_name (ClD (ClassDecl _ cname _ sigs _ _ src_loc))
+ = new_name cname src_loc `thenRn` \ class_name ->
+ mapRn (getClassOpNames new_name) sigs `thenRn` \ sub_names ->
+ returnRn (AvailTC class_name (class_name : sub_names))
+
+getDeclBinders new_name (SigD (IfaceSig var ty prags src_loc))
+ = new_name var src_loc `thenRn` \ var_name ->
+ returnRn (Avail var_name)
+
+getDeclBinders new_name (DefD _) = returnRn NotAvailable
+getDeclBinders new_name (InstD _) = returnRn NotAvailable
+
+----------------
+getConFieldNames new_name (ConDecl con _ src_loc : rest)
+ = new_name con src_loc `thenRn` \ n ->
+ getConFieldNames new_name rest `thenRn` \ ns ->
+ returnRn (n:ns)
+
+getConFieldNames new_name (NewConDecl con _ src_loc : rest)
+ = new_name con src_loc `thenRn` \ n ->
+ getConFieldNames new_name rest `thenRn` \ ns ->
+ returnRn (n:ns)
+
+getConFieldNames new_name (ConOpDecl _ con _ src_loc : rest)
+ = new_name con src_loc `thenRn` \ n ->
+ getConFieldNames new_name rest `thenRn` \ ns ->
+ returnRn (n:ns)
+
+getConFieldNames new_name (RecConDecl con fielddecls src_loc : rest)
+ = mapRn (\n -> new_name n src_loc) (con:fields) `thenRn` \ cfs ->
+ getConFieldNames new_name rest `thenRn` \ ns ->
+ returnRn (cfs ++ ns)
+ where
+ fields = concat (map fst fielddecls)
+
+getConFieldNames new_name [] = returnRn []
+
+getClassOpNames new_name (ClassOpSig op _ _ src_loc) = new_name op src_loc
+\end{code}
+
+
+%*********************************************************
+%* *
+\subsection{Reading an interface file}
+%* *
+%*********************************************************
+
+\begin{code}
+findAndReadIface :: Pretty -> Module -> RnMG (Maybe ParsedIface)
+ -- Nothing <=> file not found, or unreadable, or illegible
+ -- Just x <=> successfully found and parsed
+findAndReadIface doc_str mod
+ = traceRn trace_msg `thenRn_`
+ getSearchPathRn `thenRn` \ dirs ->
+ try dirs dirs
+ where
+ trace_msg = ppHang (ppBesides [ppPStr SLIT("Reading interface for "),
+ pprModule PprDebug mod, ppSemi])
+ 4 (ppBesides [ppPStr SLIT("reason: "), doc_str])
+
+ mod_str = moduleString mod
+ hisuf =
+ if isPreludeModule mod then
+ case opt_HiSuffixPrelude of { Just hisuf -> hisuf; _ -> ".hi"}
+ else
+ case opt_HiSuffix of {Just hisuf -> hisuf; _ -> ".hi"}
+
+ try all_dirs [] = traceRn (ppPStr SLIT("...failed")) `thenRn_`
+ returnRn Nothing
+
+ try all_dirs (dir:dirs)
+ = readIface file_path `thenRn` \ read_result ->
+ case read_result of
+ Nothing -> try all_dirs dirs
+ Just iface -> traceRn (ppPStr SLIT("...done")) `thenRn_`
+ returnRn (Just iface)
+ where
+ file_path = dir ++ "/" ++ moduleString mod ++ hisuf
+\end{code}
+
+@readIface@ trys just one file.
+
+\begin{code}
+readIface :: String -> RnMG (Maybe ParsedIface)
+ -- Nothing <=> file not found, or unreadable, or illegible
+ -- Just x <=> successfully found and parsed
+readIface file_path
+ = ioToRnMG (hGetStringBuffer file_path) `thenRn` \ read_result ->
+--OLD: = ioToRnMG (readFile file_path) `thenRn` \ read_result ->
+ case read_result of
+ Right contents -> case parseIface contents of
+ Failed err -> --ioToRnMG (freeStringBuffer contents) `thenRn` \ _ ->
+ failWithRn Nothing err
+ Succeeded iface -> --ioToRnMG (freeStringBuffer contents) `thenRn` \ _ ->
+ returnRn (Just iface)
+
+ Left (NoSuchThing _) -> returnRn Nothing
+
+ Left err -> failWithRn Nothing
+ (cannaeReadFile file_path err)
+
+\end{code}
+
+mkSearchPath takes a string consisting of a colon-separated list of directories, and turns it into
+a list of directories. For example:
+
+ mkSearchPath "foo:.:baz" = ["foo", ".", "baz"]
+
+\begin{code}
+mkSearchPath :: Maybe String -> SearchPath
+mkSearchPath Nothing = ["."]
+mkSearchPath (Just s)
+ = go s
+ where
+ go "" = []
+ go s = first : go (drop 1 rest)
+ where
+ (first,rest) = span (/= ':') s
+\end{code}
+
+%*********************************************************
+%* *
+\subsection{Errors}
+%* *
+%*********************************************************
+
+\begin{code}