+
+%*********************************************************
+%* *
+\subsection{Loading a new interface file}
+%* *
+%*********************************************************
+
+\begin{code}
+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 pprModuleName mods)) `thenRn_`
+ mapRn_ load mods `thenRn_`
+ returnRn ()
+ where
+ load mod = loadInterface (mk_doc mod) mod ImportBySystem
+ mk_doc mod = pprModuleName 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_resultb ->
+ 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 } &&
+ isLocalModule 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_vers, fix_env) ->
+ foldlRn (loadDeprec mod) emptyDeprecEnv (pi_deprecs iface) `thenRn` \ deprec_env ->
+ foldlRn (loadInstDecl mod) (iInsts ifaces) (pi_insts iface) `thenRn` \ new_insts ->
+ loadExports (pi_exports iface) `thenRn` \ avails ->
+ let
+ version = VersionInfo { modVers = pi_vers iface,
+ fixVers = fix_vers,
+ ruleVers = rule_vers,
+ declVers = decl_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 (pi_orphan iface, hi_boot_file, True)
+
+ -- Now add info about this module to the PST
+ new_pst = extendModuleEnv pst mod mod_detils
+ mod_details = ModDetails { mdModule = mod, mvVersion = version,
+ mdExports = avails,
+ mdFixEnv = fix_env, mdDeprecEnv = deprec_env }
+
+ new_ifaces = ifaces { iPST = new_pst,
+ 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 -> PackageSymbolTable -> [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))
+ filtered_new_deps
+ | isLocalModule 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 :: [ExportItem] -> RnM d Avails
+loadExports items
+ = getModuleRn `thenRn` \ this_mod ->
+ mapRn (loadExport this_mod) items `thenRn` \ avails_s ->
+ returnRn (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
+ where
+ new_name mod occ = newGlobalName mod occ
+
+ load_entity mod (Avail occ)
+ = new_name mod occ `thenRn` \ name ->
+ returnRn (Avail name)
+ load_entity mod (AvailTC occ occs)
+ = new_name mod occ `thenRn` \ name ->
+ mapRn (new_name mod) occs `thenRn` \ names ->
+ returnRn (AvailTC name names)
+
+
+-----------------------------------------------------
+-- Loading type/class/value decls
+-----------------------------------------------------
+
+loadDecls :: Module
+ -> DeclsMap
+ -> [(Version, RdrNameHsDecl)]
+ -> RnM d (NameEnv Version, DeclsMap)
+loadDecls mod decls_map decls
+ = foldlRn (loadDecl mod) (emptyNameEnv, decls_map) decls
+
+loadDecl :: Module
+ -> (NameEnv Version, DeclsMap)
+ -> (Version, RdrNameHsDecl)
+ -> RnM d (NameEnv Version, DeclsMap)
+loadDecl mod (version_map, decls_map) (version, decl)
+ = getDeclBinders new_name decl `thenRn` \ maybe_avail ->
+ case maybe_avail of {
+ Nothing -> returnRn (version_map, decls_map); -- No bindings
+ Just avail ->
+
+ getDeclSysBinders new_name decl `thenRn` \ sys_bndrs ->
+ let
+ full_avail = addSysAvails avail sys_bndrs
+ -- Add the sys-binders to avail. When we import the decl,
+ -- it's full_avail that will get added to the 'already-slurped' set (iSlurp)
+ -- If we miss out sys-binders, we'll read the decl multiple times!
+
+ main_name = availName avail
+ new_decls_map = foldl add_decl decls_map
+ [ (name, (full_avail, name==main_name, (mod, decl')))
+ | name <- availNames full_avail]
+ add_decl decls_map (name, stuff)
+ = WARN( name `elemNameEnv` decls_map, ppr name )
+ extendNameEnv decls_map name stuff
+
+ new_version_map = extendNameEnv version_map main_name version
+ in
+ returnRn (new_version_map, new_decls_map)
+ }
+ where
+ -- newTopBinder puts into the cache the binder with the
+ -- module information set correctly. When the decl is later renamed,
+ -- the binding site will thereby get the correct module.
+ -- There maybe occurrences that don't have the correct Module, but
+ -- by the typechecker will propagate the binding definition to all
+ -- the occurrences, so that doesn't matter
+ new_name rdr_name loc = newTopBinder mod rdr_name loc
+
+ {-
+ If a signature decl is being loaded, and optIgnoreIfacePragmas is on,
+ we toss away unfolding information.
+
+ Also, if the signature is loaded from a module we're importing from source,
+ we do the same. This is to avoid situations when compiling a pair of mutually
+ recursive modules, peering at unfolding info in the interface file of the other,
+ e.g., you compile A, it looks at B's interface file and may as a result change
+ its interface file. Hence, B is recompiled, maybe changing its interface file,
+ which will the unfolding info used in A to become invalid. Simple way out is to
+ just ignore unfolding info.
+
+ [Jan 99: I junked the second test above. If we're importing from an hi-boot
+ file there isn't going to *be* any pragma info. Maybe the above comment
+ dates from a time where we picked up a .hi file first if it existed?]
+ -}
+ decl' = case decl of
+ SigD (IfaceSig name tp ls loc) | opt_IgnoreIfacePragmas
+ -> SigD (IfaceSig name tp [] loc)
+ other -> decl
+
+-----------------------------------------------------
+-- Loading fixity decls
+-----------------------------------------------------
+
+loadFixDecls mod_name (version, decls)
+ | null decls = returnRn (version, emptyNameEnv)
+
+ | otherwise
+ = mapRn (loadFixDecl mod_name) decls `thenRn` \ to_add ->
+ returnRn (version, mkNameEnv to_add)
+
+loadFixDecl mod_name sig@(FixitySig rdr_name fixity loc)
+ = newGlobalName mod_name (rdrNameOcc rdr_name) `thenRn` \ name ->
+ returnRn (name, FixitySig name fixity loc)
+
+
+-----------------------------------------------------
+-- Loading instance decls
+-----------------------------------------------------
+
+loadInstDecl :: Module
+ -> IfaceInsts
+ -> RdrNameInstDecl
+ -> RnM d IfaceInsts
+loadInstDecl mod insts decl@(InstDecl inst_ty binds uprags dfun_name src_loc)
+ =
+ -- Find out what type constructors and classes are "gates" for the
+ -- instance declaration. If all these "gates" are slurped in then
+ -- we should slurp the instance decl too.
+ --
+ -- We *don't* want to count names in the context part as gates, though.
+ -- For example:
+ -- instance Foo a => Baz (T a) where ...
+ --
+ -- Here the gates are Baz and T, but *not* Foo.
+ let
+ munged_inst_ty = removeContext inst_ty
+ free_names = extractHsTyRdrNames munged_inst_ty
+ in
+ setModuleRn mod $
+ mapRn lookupOrigName free_names `thenRn` \ gate_names ->
+ returnRn ((mkNameSet gate_names, (mod, InstD decl)) `consBag` insts)
+
+
+-- In interface files, the instance decls now look like
+-- forall a. Foo a -> Baz (T a)
+-- so we have to strip off function argument types as well
+-- as the bit before the '=>' (which is always empty in interface files)
+removeContext (HsForAllTy tvs cxt ty) = HsForAllTy tvs [] (removeFuns ty)
+removeContext ty = removeFuns ty
+
+removeFuns (HsFunTy _ ty) = removeFuns ty
+removeFuns ty = ty
+
+
+-----------------------------------------------------
+-- Loading Rules
+-----------------------------------------------------
+
+loadRules :: Module -> IfaceRules
+ -> (Version, [RdrNameRuleDecl])
+ -> RnM d (Version, IfaceRules)
+loadRules mod rule_bag (version, rules)
+ | null rules || opt_IgnoreIfacePragmas
+ = returnRn (version, rule_bag)
+ | otherwise
+ = setModuleRn mod $
+ mapRn (loadRule mod) rules `thenRn` \ new_rules ->
+ returnRn (version, rule_bag `unionBags` listToBag new_rules)
+
+loadRule :: Module -> RdrNameRuleDecl -> RnM d GatedDecl
+-- "Gate" the rule simply by whether the rule variable is
+-- needed. We can refine this later.
+loadRule mod decl@(IfaceRule _ _ var _ _ src_loc)
+ = lookupOrigName var `thenRn` \ var_name ->
+ returnRn (unitNameSet var_name, (mod, RuleD decl))
+
+loadBuiltinRules :: [(RdrName, CoreRule)] -> RnMG ()
+loadBuiltinRules builtin_rules
+ = getIfacesRn `thenRn` \ ifaces ->
+ mapRn loadBuiltinRule builtin_rules `thenRn` \ rule_decls ->
+ setIfacesRn (ifaces { iRules = iRules ifaces `unionBags` listToBag rule_decls })
+
+loadBuiltinRule (var, rule)
+ = lookupOrigName var `thenRn` \ var_name ->
+ returnRn (unitNameSet var_name, (nameModule var_name, RuleD (IfaceRuleOut var rule)))
+
+
+-----------------------------------------------------
+-- Loading Deprecations
+-----------------------------------------------------
+
+loadDeprec :: Module -> DeprecationEnv -> RdrNameDeprecation -> RnM d DeprecationEnv
+loadDeprec mod deprec_env (Deprecation (IEModuleContents _) txt _)
+ = traceRn (text "module deprecation not yet implemented:" <+> ppr mod <> colon <+> ppr txt) `thenRn_`
+ -- SUP: TEMPORARY HACK, ignoring module deprecations for now
+ returnRn deprec_env
+
+loadDeprec mod deprec_env (Deprecation ie txt _)
+ = setModuleRn mod $
+ mapRn lookupOrigName (ieNames ie) `thenRn` \ names ->
+ traceRn (text "loaded deprecation(s) for" <+> hcat (punctuate comma (map ppr names)) <> colon <+> ppr txt) `thenRn_`
+ returnRn (extendNameEnvList deprec_env (zip names (repeat txt)))