+loadHomeInterface :: SDoc -> Name -> RnM d Ifaces
+loadHomeInterface doc_str name
+ = loadInterface doc_str (moduleName (nameModule name)) ImportBySystem
+
+loadOrphanModules :: [ModuleName] -> RnM d ()
+loadOrphanModules mods
+ | null mods = returnRn ()
+ | otherwise = traceRn (text "Loading orphan modules:" <+>
+ fsep (map ppr mods)) `thenRn_`
+ mapRn_ load mods `thenRn_`
+ returnRn ()
+ where
+ load mod = loadInterface (mk_doc mod) mod ImportBySystem
+ mk_doc mod = ppr mod <+> ptext SLIT("is a orphan-instance module")
+
+
+loadInterface :: SDoc -> ModuleName -> WhereFrom -> RnM d Ifaces
+loadInterface doc mod from
+ = tryLoadInterface doc mod from `thenRn` \ (ifaces, maybe_err) ->
+ case maybe_err of
+ Nothing -> returnRn ifaces
+ Just err -> failWithRn ifaces err
+
+tryLoadInterface :: SDoc -> ModuleName -> WhereFrom -> RnM d (Ifaces, Maybe Message)
+ -- Returns (Just err) if an error happened
+ -- Guarantees to return with iImpModInfo m --> (... Just cts)
+ -- (If the load fails, we plug in a vanilla placeholder
+tryLoadInterface doc_str mod_name from
+ = getIfacesRn `thenRn` \ ifaces ->
+ let
+ mod_map = iImpModInfo ifaces
+ mod_info = lookupFM mod_map mod_name
+
+ hi_boot_file
+ = case (from, mod_info) of
+ (ImportByUser, _) -> False -- Not hi-boot
+ (ImportByUserSource, _) -> True -- hi-boot
+ (ImportBySystem, Just (_, is_boot, _)) -> is_boot --
+ (ImportBySystem, Nothing) -> False
+ -- We're importing a module we know absolutely
+ -- nothing about, so we assume it's from
+ -- another package, where we aren't doing
+ -- dependency tracking. So it won't be a hi-boot file.
+
+ redundant_source_import
+ = case (from, mod_info) of
+ (ImportByUserSource, Just (_,False,_)) -> True
+ other -> False
+ in
+ -- CHECK WHETHER WE HAVE IT ALREADY
+ case mod_info of {
+ Just (_, _, True)
+ -> -- We're read it already so don't re-read it
+ returnRn (ifaces, Nothing) ;
+
+ _ ->
+
+ -- Issue a warning for a redundant {- SOURCE -} import
+ -- NB that we arrange to read all the ordinary imports before
+ -- any of the {- SOURCE -} imports
+ warnCheckRn (not redundant_source_import)
+ (warnRedundantSourceImport mod_name) `thenRn_`
+
+ -- READ THE MODULE IN
+ findAndReadIface doc_str mod_name hi_boot_file `thenRn` \ read_result ->
+ case read_result of {
+ Left err -> -- Not found, so add an empty export env to the Ifaces map
+ -- so that we don't look again
+ let
+ new_mod_map = addToFM mod_map mod_name (False, False, True)
+ new_ifaces = ifaces { iImpModInfo = new_mod_map }
+ in
+ setIfacesRn new_ifaces `thenRn_`
+ returnRn (new_ifaces, Just err) ;
+
+ -- Found and parsed!
+ Right (mod, iface) ->
+
+ -- LOAD IT INTO Ifaces
+
+ -- NB: *first* we do loadDecl, so that the provenance of all the locally-defined
+ --- names is done correctly (notably, whether this is an .hi file or .hi-boot file).
+ -- If we do loadExport first the wrong info gets into the cache (unless we
+ -- explicitly tag each export which seems a bit of a bore)
+
+
+ -- Sanity check. If we're system-importing a module we know nothing at all
+ -- about, it should be from a different package to this one
+ WARN( not (maybeToBool mod_info) &&
+ case from of { ImportBySystem -> True; other -> False } &&
+ isModuleInThisPackage mod,
+ ppr mod )
+
+ loadDecls mod (iDecls ifaces) (pi_decls iface) `thenRn` \ (decls_vers, new_decls) ->
+ loadRules mod (iRules ifaces) (pi_rules iface) `thenRn` \ (rule_vers, new_rules) ->
+ loadFixDecls mod_name (pi_fixity iface) `thenRn` \ fix_env ->
+ loadDeprecs mod (pi_deprecs iface) `thenRn` \ deprec_env ->
+ foldlRn (loadInstDecl mod) (iInsts ifaces) (pi_insts iface) `thenRn` \ new_insts ->
+ loadExports (pi_exports iface) `thenRn` \ (export_vers, avails) ->
+ let
+ version = VersionInfo { vers_module = pi_vers iface,
+ vers_exports = export_vers,
+ vers_rules = rule_vers,
+ vers_decls = decls_vers }
+
+ -- For an explicit user import, add to mod_map info about
+ -- the things the imported module depends on, extracted
+ -- from its usage info.
+ mod_map1 = case from of
+ ImportByUser -> addModDeps mod (pi_usages iface) mod_map
+ other -> mod_map
+ mod_map2 = addToFM mod_map1 mod_name (has_orphans, hi_boot_file, True)
+
+ -- Now add info about this module to the PIT
+ has_orphans = pi_orphan iface
+ new_pit = extendModuleEnv (iPIT ifaces) mod mod_iface
+ mod_iface = ModIface { mi_module = mod, mi_version = version,
+ mi_exports = avails, mi_orphan = has_orphans,
+ mi_fixities = fix_env, mi_deprecs = deprec_env,
+ mi_usages = [], -- Will be filled in later
+ mi_decls = panic "No mi_decls in PIT",
+ mi_globals = panic "No mi_globals in PIT"
+ }
+
+ new_ifaces = ifaces { iPIT = new_pit,
+ iDecls = new_decls,
+ iInsts = new_insts,
+ iRules = new_rules,
+ iImpModInfo = mod_map2 }
+ in
+ setIfacesRn new_ifaces `thenRn_`
+ returnRn (new_ifaces, Nothing)
+ }}
+
+-----------------------------------------------------
+-- Adding module dependencies from the
+-- import decls in the interface file
+-----------------------------------------------------
+
+addModDeps :: Module -> [ImportVersion a]
+ -> ImportedModuleInfo -> ImportedModuleInfo
+-- (addModDeps M ivs deps)
+-- We are importing module M, and M.hi contains 'import' decls given by ivs
+addModDeps mod new_deps mod_deps
+ = foldr add mod_deps filtered_new_deps
+ where
+ -- Don't record dependencies when importing a module from another package
+ -- Except for its descendents which contain orphans,
+ -- and in that case, forget about the boot indicator
+ filtered_new_deps :: [(ModuleName, (WhetherHasOrphans, IsBootInterface, IsLoaded))]
+ filtered_new_deps
+ | isModuleInThisPackage mod
+ = [ (imp_mod, (has_orphans, is_boot, False))
+ | (imp_mod, has_orphans, is_boot, _) <- new_deps
+ ]
+ | otherwise = [ (imp_mod, (True, False, False))
+ | (imp_mod, has_orphans, _, _) <- new_deps,
+ has_orphans
+ ]
+ add (imp_mod, dep) deps = addToFM_C combine deps imp_mod dep
+
+ combine old@(_, old_is_boot, old_is_loaded) new
+ | old_is_loaded || not old_is_boot = old -- Keep the old info if it's already loaded
+ -- or if it's a non-boot pending load
+ | otherwise = new -- Otherwise pick new info
+
+
+-----------------------------------------------------
+-- Loading the export list
+-----------------------------------------------------
+
+loadExports :: (Version, [ExportItem]) -> RnM d (Version, Avails)
+loadExports (vers, items)
+ = getModuleRn `thenRn` \ this_mod ->
+ mapRn (loadExport this_mod) items `thenRn` \ avails_s ->
+ returnRn (vers, concat avails_s)
+
+
+loadExport :: Module -> ExportItem -> RnM d [AvailInfo]
+loadExport this_mod (mod, entities)
+ | mod == moduleName this_mod = returnRn []
+ -- If the module exports anything defined in this module, just ignore it.
+ -- Reason: otherwise it looks as if there are two local definition sites
+ -- for the thing, and an error gets reported. Easiest thing is just to
+ -- filter them out up front. This situation only arises if a module
+ -- imports itself, or another module that imported it. (Necessarily,
+ -- this invoves a loop.) Consequence: if you say
+ -- module A where
+ -- import B( AType )
+ -- type AType = ...
+ --
+ -- module B( AType ) where
+ -- import {-# SOURCE #-} A( AType )
+ --
+ -- then you'll get a 'B does not export AType' message. A bit bogus
+ -- but it's a bogus thing to do!
+
+ | otherwise
+ = mapRn (load_entity mod) entities