\begin{code}
module LoadIface (
loadInterface, loadInterfaceForName, loadWiredInHomeIface,
- loadSrcInterface, loadSysInterface, loadOrphanModules,
+ loadSrcInterface, loadSysInterface, loadUserInterface, loadOrphanModules,
findAndReadIface, readIface, -- Used when reading the module's old interface
loadDecls, -- Should move to TcIface and be renamed
initExternalPackageState,
#include "HsVersions.h"
import {-# SOURCE #-} TcIface( tcIfaceDecl, tcIfaceRules, tcIfaceInst,
- tcIfaceFamInst, tcIfaceVectInfo )
+ tcIfaceFamInst, tcIfaceVectInfo, tcIfaceAnnotations )
import DynFlags
import IfaceSyn
import BasicTypes hiding (SuccessFlag(..))
import TcRnMonad
-import Type
import PrelNames
import PrelInfo
import PrelRules
import Rules
+import Annotations
import InstEnv
import FamInstEnv
import Name
import NameEnv
-import MkId
import Module
-import OccName
import Maybes
import ErrUtils
import Finder
-import LazyUniqFM
+import UniqFM
import StaticFlags
import Outputable
import BinIface
import Fingerprint
import Control.Monad
-import Data.List
-import Data.Maybe
\end{code}
-- | An 'IfM' function to load the home interface for a wired-in thing,
-- so that we're sure that we see its instance declarations and rules
--- See Note [Loading instances]
+-- See Note [Loading instances for wired-in things] in TcIface
loadWiredInHomeIface :: Name -> IfM lcl ()
loadWiredInHomeIface name
= ASSERT( isWiredInName name )
- do loadSysInterface doc (nameModule name); return ()
+ do _ <- loadSysInterface doc (nameModule name); return ()
where
doc = ptext (sLit "Need home interface for wired-in thing") <+> ppr name
--- | A wrapper for 'loadInterface' that throws an exception if it fails
+-- | Loads a system interface and throws an exception if it fails
loadSysInterface :: SDoc -> Module -> IfM lcl ModIface
-loadSysInterface doc mod_name
- = do { mb_iface <- loadInterface doc mod_name ImportBySystem
+loadSysInterface doc mod_name = loadInterfaceWithException doc mod_name ImportBySystem
+
+-- | Loads a user interface and throws an exception if it fails. The first parameter indicates
+-- whether we should import the boot variant of the module
+loadUserInterface :: Bool -> SDoc -> Module -> IfM lcl ModIface
+loadUserInterface is_boot doc mod_name = loadInterfaceWithException doc mod_name (ImportByUser is_boot)
+
+-- | A wrapper for 'loadInterface' that throws an exception if it fails
+loadInterfaceWithException :: SDoc -> Module -> WhereFrom -> IfM lcl ModIface
+loadInterfaceWithException doc mod_name where_from
+ = do { mb_iface <- loadInterface doc mod_name where_from
; case mb_iface of
Failed err -> ghcError (ProgramError (showSDoc err))
Succeeded iface -> return iface }
\end{code}
-Note [Loading instances]
-~~~~~~~~~~~~~~~~~~~~~~~~
-We need to make sure that we have at least *read* the interface files
-for any module with an instance decl or RULE that we might want.
-
-* If the instance decl is an orphan, we have a whole separate mechanism
- (loadOprhanModules)
-
-* If the instance decl not an orphan, then the act of looking at the
- TyCon or Class will force in the defining module for the
- TyCon/Class, and hence the instance decl
-
-* BUT, if the TyCon is a wired-in TyCon, we don't really need its interface;
- but we must make sure we read its interface in case it has instances or
- rules. That is what LoadIface.loadWiredInHomeInterface does. It's called
- from TcIface.{tcImportDecl, checkWiredInTyCon, ifCHeckWiredInThing}
-
-All of this is done by the type checker. The renamer plays no role.
-(It used to, but no longer.)
-
-
%*********************************************************
%* *
-- if an earlier import had a before we got to real imports. I think.
_ -> do {
- let { hi_boot_file = case from of
- ImportByUser usr_boot -> usr_boot
- ImportBySystem -> sys_boot
-
- ; mb_dep = lookupUFM (eps_is_boot eps) (moduleName mod)
- ; sys_boot = case mb_dep of
- Just (_, is_boot) -> is_boot
- Nothing -> False
- -- The boot-ness of the requested interface,
- } -- based on the dependencies in directly-imported modules
-
-- READ THE MODULE IN
- ; read_result <- findAndReadIface doc_str mod hi_boot_file
+ ; read_result <- case (wantHiBootFile dflags eps mod from) of
+ Failed err -> return (Failed err)
+ Succeeded hi_boot_file -> findAndReadIface doc_str mod hi_boot_file
; case read_result of {
Failed err -> do
{ let fake_iface = emptyModIface mod
; return (Failed err) } ;
-- Found and parsed!
- Succeeded (iface, file_path) -- Sanity check:
- | ImportBySystem <- from, -- system-importing...
- modulePackageId (mi_module iface) == thisPackage dflags,
- -- a home-package module...
- Nothing <- mb_dep -- that we know nothing about
- -> return (Failed (badDepMsg mod))
-
- | otherwise ->
+ -- We used to have a sanity check here that looked for:
+ -- * System importing ..
+ -- * a home package module ..
+ -- * that we know nothing about (mb_dep == Nothing)!
+ --
+ -- But this is no longer valid because thNameToGhcName allows users to
+ -- cause the system to load arbitrary interfaces (by supplying an appropriate
+ -- Template Haskell original-name).
+ Succeeded (iface, file_path) ->
let
loc_doc = text file_path
; new_eps_insts <- mapM tcIfaceInst (mi_insts iface)
; new_eps_fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface)
; new_eps_rules <- tcIfaceRules ignore_prags (mi_rules iface)
+ ; new_eps_anns <- tcIfaceAnnotations (mi_anns iface)
; new_eps_vect_info <- tcIfaceVectInfo mod (mkNameEnv new_eps_decls)
(mi_vect_info iface)
mi_decls = panic "No mi_decls in PIT",
mi_insts = panic "No mi_insts in PIT",
mi_fam_insts = panic "No mi_fam_insts in PIT",
- mi_rules = panic "No mi_rules in PIT"
+ mi_rules = panic "No mi_rules in PIT",
+ mi_anns = panic "No mi_anns in PIT"
}
}
; updateEps_ $ \ eps ->
+ if elemModuleEnv mod (eps_PIT eps) then eps else
eps {
eps_PIT = extendModuleEnv (eps_PIT eps) mod final_iface,
eps_PTE = addDeclsToPTE (eps_PTE eps) new_eps_decls,
new_eps_fam_insts,
eps_vect_info = plusVectInfo (eps_vect_info eps)
new_eps_vect_info,
+ eps_ann_env = extendAnnEnvList (eps_ann_env eps)
+ new_eps_anns,
eps_mod_fam_inst_env
= let
fam_inst_env =
; return (Succeeded final_iface)
}}}}
+wantHiBootFile :: DynFlags -> ExternalPackageState -> Module -> WhereFrom
+ -> MaybeErr Message IsBootInterface
+-- Figure out whether we want Foo.hi or Foo.hi-boot
+wantHiBootFile dflags eps mod from
+ = case from of
+ ImportByUser usr_boot
+ | usr_boot && not this_package
+ -> Failed (badSourceImport mod)
+ | otherwise -> Succeeded usr_boot
+
+ ImportBySystem
+ | not this_package -- If the module to be imported is not from this package
+ -> Succeeded False -- don't look it up in eps_is_boot, because that is keyed
+ -- on the ModuleName of *home-package* modules only.
+ -- We never import boot modules from other packages!
+
+ | otherwise
+ -> case lookupUFM (eps_is_boot eps) (moduleName mod) of
+ Just (_, is_boot) -> Succeeded is_boot
+ Nothing -> Succeeded False
+ -- The boot-ness of the requested interface,
+ -- based on the dependencies in directly-imported modules
+ where
+ this_package = thisPackage dflags == modulePackageId mod
+
+badSourceImport :: Module -> SDoc
+badSourceImport mod
+ = hang (ptext (sLit "You cannot {-# SOURCE #-} import a module from another package"))
+ 2 (ptext (sLit "but") <+> quotes (ppr mod) <+> ptext (sLit "is from package")
+ <+> quotes (ppr (modulePackageId mod)))
+\end{code}
+
+{-
+Used to be used for the loadInterface sanity check on system imports. That has been removed, but I'm leaving this in pending
+review of this decision by SPJ - MCB 10/2008
+
badDepMsg :: Module -> SDoc
badDepMsg mod
= hang (ptext (sLit "Interface file inconsistency:"))
2 (sep [ptext (sLit "home-package module") <+> quotes (ppr mod) <+> ptext (sLit "is needed,"),
ptext (sLit "but is not listed in the dependencies of the interfaces directly imported by the module being compiled")])
+-}
+\begin{code}
-----------------------------------------------------
-- Loading type/class/value decls
-- We pass the full Module name here, replete with
-- Found file, so read it
{ let { file_path = addBootSuffix_maybe hi_boot_file (ml_hi_file loc) }
+ -- If the interface is in the current package then if we could
+ -- load it would already be in the HPT and we assume that our
+ -- callers checked that.
; if thisPackage dflags == modulePackageId mod
&& not (isOneShot (ghcMode dflags))
then return (Failed (homeModError mod loc))
eps_mod_fam_inst_env
= emptyModuleEnv,
eps_vect_info = noVectInfo,
+ eps_ann_env = emptyAnnEnv,
eps_stats = EpsStats { n_ifaces_in = 0, n_decls_in = 0, n_decls_out = 0
, n_insts_in = 0, n_insts_out = 0
, n_rules_in = length builtinRules, n_rules_out = 0 }
, vcat (map pprExport (mi_exports iface))
, pprDeps (mi_deps iface)
, vcat (map pprUsage (mi_usages iface))
+ , vcat (map pprIfaceAnnotation (mi_anns iface))
, pprFixities (mi_fixities iface)
, vcat (map pprIfaceDecl (mi_decls iface))
, vcat (map ppr (mi_insts iface))
pprWarns (WarnSome prs) = ptext (sLit "Warnings")
<+> vcat (map pprWarning prs)
where pprWarning (name, txt) = ppr name <+> ppr txt
+
+pprIfaceAnnotation :: IfaceAnnotation -> SDoc
+pprIfaceAnnotation (IfaceAnnotation { ifAnnotatedTarget = target, ifAnnotatedValue = serialized })
+ = ppr target <+> ptext (sLit "annotated by") <+> ppr serialized
\end{code}