[project @ 1997-01-17 00:32:23 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / RnIfaces.lhs
index 9745409..b6f4521 100644 (file)
 #include "HsVersions.h"
 
 module RnIfaces (
-       findHiFiles,
-       cacheInterface,
-       readInterface,
-       rnInterfaces,
-       finalIfaceInfo,
-       IfaceCache(..),
-       VersionInfo(..),
-       ParsedIface(..)
-    ) where
+       getInterfaceExports,
+       getImportedInstDecls,
+       getSpecialInstModules,
+       getDecl, getWiredInDecl,
+       getImportVersions,
+
+       checkUpToDate,
 
-import PreludeGlaST    ( returnPrimIO, thenPrimIO,
-                         readVar, writeVar, MutableVar(..) )
+       getDeclBinders,
+       mkSearchPath
+    ) where
 
-import Ubiq
+IMP_Ubiq()
 
-import HsSyn
-import RdrHsSyn
-import RnHsSyn
 
+import HsSyn           ( HsDecl(..), TyDecl(..), ClassDecl(..), HsTyVar, Bind, HsExpr, Sig(..), 
+                         HsBinds(..), MonoBinds, DefaultDecl, ConDecl(..), HsType, BangType, IfaceSig(..),
+                         FixityDecl(..), Fixity, Fake, InPat, InstDecl(..), SYN_IE(Version), HsIdInfo
+                       )
+import HsPragmas       ( noGenPragmas )
+import RdrHsSyn                ( SYN_IE(RdrNameHsDecl), SYN_IE(RdrNameInstDecl), 
+                         RdrName, rdrNameOcc
+                       )
+import RnEnv           ( newGlobalName, lookupRn, addImplicitOccsRn, availNames )
+import RnSource                ( rnHsType )
 import RnMonad
-import RnUtils         ( RnEnv(..) )
+import ParseIface      ( parseIface )
 
-import Bag             ( emptyBag )
-import ErrUtils                ( Error(..), Warning(..) )
-import FiniteMap       ( emptyFM, lookupFM, addToFM )
+import ErrUtils                ( SYN_IE(Error), SYN_IE(Warning) )
+import FiniteMap       ( FiniteMap, emptyFM, unitFM, lookupFM, addToFM, addListToFM, fmToList )
+import Name            ( Name {-instance NamedThing-}, Provenance, OccName(..),
+                         modAndOcc, occNameString, moduleString, pprModule,
+                         NameSet(..), emptyNameSet, unionNameSets, nameSetToList,
+                         minusNameSet, mkNameSet,
+                         isWiredInName, maybeWiredInTyConName, maybeWiredInIdName
+                        )
+import Id              ( GenId, Id(..), idType, dataConTyCon, isDataCon )
+import TyCon           ( TyCon, tyConDataCons, isSynTyCon, getSynTyConDefn )
+import Type            ( namesOfType )
+import TyVar           ( GenTyVar )
+import SrcLoc          ( mkIfaceSrcLoc )
+import PrelMods                ( gHC__ )
+import Bag
+import Maybes          ( MaybeErr(..), expectJust, maybeToBool )
+import ListSetOps      ( unionLists )
 import Pretty
-import Maybes          ( MaybeErr(..) )
-import Util            ( panic )
+import PprStyle                ( PprStyle(..) )
+import Util            ( pprPanic )
+\end{code}
+
+
+
+%*********************************************************
+%*                                                     *
+\subsection{Loading a new interface file}
+%*                                                     *
+%*********************************************************
+
+\begin{code}
+loadInterface :: Pretty -> Module -> RnMG Ifaces
+loadInterface doc_str load_mod 
+  = getIfacesRn                `thenRn` \ ifaces ->
+    let
+       Ifaces this_mod mod_vers_map export_env_map vers_map decls_map inst_map inst_mods = ifaces
+    in
+       -- CHECK WHETHER WE HAVE IT ALREADY
+    if maybeToBool (lookupFM export_env_map load_mod) 
+    then
+       returnRn ifaces         -- Already in the cache; don't re-read it
+    else
+
+       -- READ THE MODULE IN
+    findAndReadIface doc_str load_mod          `thenRn` \ read_result ->
+    case read_result of {
+       -- Check for not found
+       Nothing ->      -- Not found, so add an empty export env to the Ifaces map
+                       -- so that we don't look again
+                  let
+                       new_export_env_map = addToFM export_env_map load_mod ([],[])
+                       new_ifaces = Ifaces this_mod mod_vers_map 
+                                           new_export_env_map 
+                                           vers_map decls_map inst_map inst_mods
+                  in
+                  setIfacesRn new_ifaces               `thenRn_`
+                  failWithRn new_ifaces (noIfaceErr load_mod) ;
+
+       -- Found and parsed!
+       Just (ParsedIface _ mod_vers usages exports rd_inst_mods fixs decls insts) ->
+
+       -- LOAD IT INTO Ifaces
+    mapRn loadExport exports                                   `thenRn` \ avails_s ->
+    foldlRn (loadDecl load_mod) (decls_map,vers_map) decls     `thenRn` \ (new_decls_map, new_vers_map) ->
+    foldlRn (loadInstDecl load_mod) inst_map insts             `thenRn` \ new_insts_map ->
+    let
+        export_env = (concat avails_s, fixs)
+
+                       -- Exclude this module from the "special-inst" modules
+        new_inst_mods = inst_mods `unionLists` (filter (/= this_mod) rd_inst_mods)
+
+        new_ifaces = Ifaces this_mod
+                            (addToFM mod_vers_map load_mod mod_vers)
+                            (addToFM export_env_map load_mod export_env)
+                            new_vers_map
+                            new_decls_map
+                            new_insts_map
+                            new_inst_mods 
+    in
+    setIfacesRn new_ifaces             `thenRn_`
+    returnRn new_ifaces
+    }
+
+loadExport :: ExportItem -> RnMG [AvailInfo]
+loadExport (mod, entities)
+  = mapRn load_entity entities
+  where
+    new_name occ = newGlobalName mod occ
+
+    load_entity (occ, occs)
+      =        new_name occ            `thenRn` \ name ->
+        mapRn new_name occs    `thenRn` \ names ->
+        returnRn (Avail name names)
+
+loadVersion :: Module -> VersionMap -> (OccName,Version) -> RnMG VersionMap
+loadVersion mod vers_map (occ, version)
+  = newGlobalName mod occ                      `thenRn` \ name ->
+    returnRn (addToFM vers_map name version)
+
+
+loadDecl :: Module -> (DeclsMap, VersionMap)
+        -> (Version, RdrNameHsDecl)
+        -> RnMG (DeclsMap, VersionMap)
+loadDecl mod (decls_map, vers_map) (version, decl)
+  = getDeclBinders new_implicit_name decl      `thenRn` \ avail@(Avail name _) ->
+    returnRn (addListToFM decls_map
+                         [(name,(avail,decl)) | name <- availNames avail],
+             addToFM vers_map name version
+    )
+  where
+    new_implicit_name rdr_name loc = newGlobalName mod (rdrNameOcc rdr_name)
+
+loadInstDecl :: Module -> Bag IfaceInst -> RdrNameInstDecl -> RnMG (Bag IfaceInst)
+loadInstDecl mod_name insts decl@(InstDecl inst_ty binds uprags dfun_name src_loc)
+  = initRnMS emptyRnEnv mod_name InterfaceMode $
+
+       -- Find out what type constructors and classes are mentioned in the
+       -- instance declaration.  We have to be a bit clever.
+       --
+       -- We want to rename the type so that we can find what
+       -- (free) type constructors are inside it.  But we must *not* thereby
+       -- put new occurrences into the global pool because otherwise we'll force
+       -- them all to be loaded.  We kill two birds with ones stone by renaming
+       -- with a fresh occurrence pool.
+    findOccurrencesRn (rnHsType inst_ty)       `thenRn` \ ty_names ->
+
+    returnRn ((ty_names, mod_name, decl) `consBag` insts)
+\end{code}
+
+
+%********************************************************
+%*                                                     *
+\subsection{Loading usage information}
+%*                                                     *
+%********************************************************
+
+\begin{code}
+checkUpToDate :: Module -> RnMG Bool           -- True <=> no need to recompile
+checkUpToDate mod_name
+  = findAndReadIface doc_str mod_name          `thenRn` \ read_result ->
+    case read_result of
+       Nothing ->      -- Old interface file not found, so we'd better bale out
+                   traceRn (ppSep [ppStr "Didnt find old iface", pprModule PprDebug mod_name]) `thenRn_`
+                   returnRn False
+
+       Just (ParsedIface _ _ usages _ _ _ _ _) 
+               ->      -- Found it, so now check it
+                   checkModUsage usages
+  where
+       -- Only look in current directory, with suffix .hi
+    doc_str = ppSep [ppStr "Need usage info from", pprModule PprDebug mod_name]
+
+
+checkModUsage [] = returnRn True               -- Yes!  Everything is up to date!
+
+checkModUsage ((mod, old_mod_vers, old_local_vers) : rest)
+  = loadInterface doc_str mod          `thenRn` \ ifaces ->
+    let
+       Ifaces _ mod_vers_map _ new_vers_map _ _ _ = ifaces
+       maybe_new_mod_vers = lookupFM mod_vers_map mod
+       Just new_mod_vers  = maybe_new_mod_vers
+    in
+       -- If we can't find a version number for the old module then
+       -- bale out saying things aren't up to date
+    if not (maybeToBool maybe_new_mod_vers) then
+       returnRn False
+    else
+
+       -- If the module version hasn't changed, just move on
+    if new_mod_vers == old_mod_vers then
+       traceRn (ppSep [ppStr "Module version unchanged:", pprModule PprDebug mod])     `thenRn_`
+       checkModUsage rest
+    else
+    traceRn (ppSep [ppStr "Module version has changed:", pprModule PprDebug mod])      `thenRn_`
+
+       -- New module version, so check entities inside
+    checkEntityUsage mod new_vers_map old_local_vers   `thenRn` \ up_to_date ->
+    if up_to_date then
+       traceRn (ppStr "...but the bits I use havn't.") `thenRn_`
+       checkModUsage rest      -- This one's ok, so check the rest
+    else
+       returnRn False          -- This one failed, so just bail out now
+  where
+    doc_str = ppSep [ppStr "need version info for", pprModule PprDebug mod]
+
+
+checkEntityUsage mod new_vers_map [] 
+  = returnRn True      -- Yes!  All up to date!
+
+checkEntityUsage mod new_vers_map ((occ_name,old_vers) : rest)
+  = newGlobalName mod occ_name         `thenRn` \ name ->
+    case lookupFM new_vers_map name of
+
+       Nothing       ->        -- We used it before, but it ain't there now
+                         traceRn (ppSep [ppStr "...and this no longer exported:", ppr PprDebug name])  `thenRn_`
+                         returnRn False
+
+       Just new_vers ->        -- It's there, but is it up to date?
+                         if new_vers == old_vers then
+                               -- Up to date, so check the rest
+                               checkEntityUsage mod new_vers_map rest
+                         else
+                               traceRn (ppSep [ppStr "...and this is out of date:", ppr PprDebug name])  `thenRn_`
+                               returnRn False  -- Out of date, so bale out
+\end{code}
+
+
+%*********************************************************
+%*                                                     *
+\subsection{Getting in a declaration}
+%*                                                     *
+%*********************************************************
+
+\begin{code}
+getDecl :: Name -> RnMG (AvailInfo, RdrNameHsDecl)
+getDecl name
+  = traceRn doc_str                    `thenRn_`
+    loadInterface doc_str mod          `thenRn` \ (Ifaces _ _ _ _ decls_map _ _) ->
+    case lookupFM decls_map name of
+
+      Just avail_w_decl -> returnRn avail_w_decl
 
+      Nothing          ->      -- Can happen legitimately for "Optional" occurrences
+                          returnRn (NotAvailable, ValD EmptyBinds)
+  where
+     (mod,_) = modAndOcc name
+     doc_str = ppSep [ppStr "Need decl for", ppr PprDebug name]
 \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,
+  *    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.
 
+  *    similarly for synonum type constructor
+
+  *    if the wired-in name is another wired-in Id, it marks as "occurrences"
+       the free vars of the Id's type.
+
+  *    it loads the interface file for the wired-in thing for the
+       sole purpose of making sure that its instance declarations are available
+
+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.
+       
 \begin{code}
-type IfaceCache = MutableVar _RealWorld (FiniteMap Module ParsedIface,
-                                        FiniteMap Module String)
+getWiredInDecl :: Name -> RnMG AvailInfo
+getWiredInDecl name
+  =    -- Force in the home module in case it has instance decls for
+       -- the thing we are interested in
+    (if not is_tycon || mod == gHC__ then
+       returnRn ()                     -- Mini hack 1: no point for non-tycons; and if we
+                                       -- do this we find PrelNum trying to import PackedString,
+                                       -- because PrelBase's .hi file mentions PackedString.unpackString
+                                       -- But PackedString.hi isn't built by that point!
+                                       --
+                                       -- Mini hack 2; GHC is guaranteed not to have
+                                       -- instance decls, so it's a waste of time
+                                       -- to read it
+    else
+       loadInterface doc_str mod       `thenRn_`
+       returnRn ()
+    )                                          `thenRn_`
+
+    if is_tycon then
+       get_wired_tycon the_tycon
+    else                               -- Must be a wired-in-Id
+    if (isDataCon the_id) then         -- ... a wired-in data constructor
+       get_wired_tycon (dataConTyCon the_id)
+    else                               -- ... a wired-in non data-constructor
+       get_wired_id the_id
+  where
+    doc_str = ppSep [ppStr "Need home module for wired in thing", ppr PprDebug name]
+    (mod,_) = modAndOcc name
+    maybe_wired_in_tycon = maybeWiredInTyConName name
+    is_tycon            = maybeToBool maybe_wired_in_tycon
+    maybe_wired_in_id    = maybeWiredInIdName    name
+    Just the_tycon      = maybe_wired_in_tycon
+    Just the_id         = maybe_wired_in_id
+
+get_wired_id id
+  = addImplicitOccsRn (nameSetToList id_mentioned)     `thenRn_`
+    returnRn (Avail (getName id) [])
+  where
+    id_mentioned        = namesOfType (idType id)
+
+get_wired_tycon tycon 
+  | isSynTyCon tycon
+  = addImplicitOccsRn (nameSetToList mentioned)                `thenRn_`
+    returnRn (Avail (getName tycon) [])
+  where
+    (tyvars,ty) = getSynTyConDefn tycon
+    mentioned = namesOfType ty `minusNameSet` mkNameSet (map getName tyvars)
 
-data ParsedIface = ParsedIface
+get_wired_tycon tycon 
+  | otherwise          -- data or newtype
+  = addImplicitOccsRn (nameSetToList mentioned)                `thenRn_`
+    returnRn (Avail (getName tycon) (map getName data_cons))
+  where
+    data_cons = tyConDataCons tycon
+    mentioned = foldr (unionNameSets . namesOfType . idType) emptyNameSet data_cons
 \end{code}
 
-*********************************************************
-*                                                      *
-\subsection{Looking for interface files}
-*                                                      *
-*********************************************************
+
+%*********************************************************
+%*                                                     *
+\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, ppStr "is directly imported"]
+
+
+getImportedInstDecls :: RnMG [IfaceInst]
+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
+    getIfacesRn                                                `thenRn` \ ifaces ->
+    let
+        Ifaces _ _ _ _ _ insts _ = ifaces
+    in
+    returnRn (bagToList insts) 
+  where
+    load_it mod = loadInterface (doc_str mod) mod
+    doc_str mod = ppSep [pprModule PprDebug mod, ppStr "is a special-instance module"]
+
+getSpecialInstModules :: RnMG [Module]
+getSpecialInstModules 
+  = getIfacesRn                                                `thenRn` \ ifaces ->
+    let
+        Ifaces _ _ _ _ _ _ inst_mods = ifaces
+    in
+    returnRn inst_mods
+\end{code}
 
 \begin{code}
-findHiFiles :: [String] -> PrimIO (FiniteMap Module String)
-findHiFiles dirs = returnPrimIO emptyFM
+getImportVersions :: [AvailInfo]                       -- Imported avails
+                 -> RnMG (VersionInfo Name)    -- Version info for these names
+
+getImportVersions imported_avails      
+  = getIfacesRn                                        `thenRn` \ ifaces ->
+    let
+        Ifaces _ mod_versions_map _ version_map _ _ _ = ifaces
+
+        -- import_versions is harder: we have to group together all the things imported
+        -- from a particular module.  We do this with yet another finite map
+
+        mv_map :: FiniteMap Module [LocalVersion Name]
+        mv_map            = foldl add_mv emptyFM imported_avails
+        add_mv mv_map (Avail name _) 
+           | isWiredInName name = mv_map       -- Don't record versions for wired-in names
+           | otherwise = case lookupFM mv_map mod of
+                               Just versions -> addToFM mv_map mod ((name,version):versions)
+                               Nothing       -> addToFM mv_map mod [(name,version)]
+           where
+            (mod,_) = modAndOcc name
+            version = case lookupFM version_map name of
+                        Just v  -> v
+                        Nothing -> pprPanic "getVersionInfo:" (ppr PprDebug name)
+
+        import_versions = [ (mod, expectJust "import_versions" (lookupFM mod_versions_map mod), local_versions)
+                          | (mod, local_versions) <- fmToList mv_map
+                          ]
+
+        -- Question: should we filter the builtins out of import_versions?
+    in
+    returnRn import_versions
 \end{code}
 
-*********************************************************
-*                                                      *
-\subsection{Reading interface files}
-*                                                      *
-*********************************************************
+%*********************************************************
+%*                                                     *
+\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}
-cacheInterface :: IfaceCache -> Module
-              -> PrimIO (MaybeErr ParsedIface Error)
-
-cacheInterface iface_var mod
-  = readVar iface_var `thenPrimIO` \ (iface_fm, file_fm) ->
-    case lookupFM iface_fm mod of
-      Just iface -> returnPrimIO (Succeeded iface)
-      Nothing    ->
-       case lookupFM file_fm mod of
-         Nothing   -> returnPrimIO (Failed (noIfaceErr mod))
-         Just file ->
-           readInterface file mod `thenPrimIO` \ read_iface ->
-           case read_iface of
-             Failed err      -> returnPrimIO (Failed err)
-             Succeeded iface ->
-               let
-                   iface_fm' = addToFM iface_fm mod iface
-               in
-               writeVar iface_var (iface_fm', file_fm) `thenPrimIO` \ _ ->
-               returnPrimIO (Succeeded iface)
-
-
-readInterface :: String -> Module
-             -> PrimIO (MaybeErr ParsedIface Error)
-
-readInterface file mod = panic "readInterface"
+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 (Avail 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 (Avail 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 (Avail 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}
-rnInterfaces ::
-          IfaceCache                           -- iface cache
-       -> RnEnv                                -- original name env
-       -> UniqSupply
-       -> RenamedHsModule                      -- module to extend with iface decls
-       -> [RnName]                             -- imported names required
-       -> PrimIO (RenamedHsModule,             -- extended module
-                  ImplicitEnv,                 -- implicit names required
-                  Bag Error,
-                  Bag Warning)
-
-rnInterfaces iface_var occ_env us rn_module todo
-  = returnPrimIO (rn_module, (emptyFM, emptyFM), emptyBag, emptyBag)
+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 [ppStr "Reading interface for ", 
+                                  pprModule PprDebug mod, ppSemi])
+                    4 (ppBesides [ppStr "reason: ", doc_str])
+
+    try all_dirs [] = traceRn (ppStr "...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 (ppStr "...done") `thenRn_`
+                             returnRn (Just iface)
+       where
+         file_path = dir ++ "/" ++ moduleString mod ++ ".hi"
 \end{code}
 
+@readIface@ trys just one file.
 
 \begin{code}
-finalIfaceInfo ::
-          IfaceCache                           -- iface cache
-       -> [RnName]                             -- all imported names required
-       -> [Module]                             -- directly imported modules
-       -> PrimIO (VersionInfo,                 -- info about version numbers
-                  [Module])                    -- special instance modules
+readIface :: String -> RnMG (Maybe ParsedIface)        
+       -- Nothing <=> file not found, or unreadable, or illegible
+       -- Just x  <=> successfully found and parsed 
+readIface file_path
+  = ioToRnMG (readFile file_path)      `thenRn` \ read_result ->
+    case read_result of
+       Right contents    -> case parseIface contents of
+                               Failed err      -> failWithRn Nothing err 
+                               Succeeded iface -> returnRn (Just iface)
+
+       Left  (NoSuchThing _) -> returnRn Nothing
 
-type VersionInfo = [(Module, Version, [(FAST_STRING, Version)])]
+       Left  err             -> failWithRn Nothing
+                                           (cannaeReadFile file_path err)
 
-finalIfaceInfo iface_var imps_reqd imp_mods
-  = returnPrimIO ([], [])
 \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}
 noIfaceErr mod sty
-  = ppCat [ppStr "Could not find interface for", ppPStr mod]
+  = ppBesides [ppStr "Could not find interface for ", ppQuote (pprModule sty mod)]
+--     , ppStr " in"]) 4 (ppAboves (map ppStr dirs))
+
+cannaeReadFile file err sty
+  = ppBesides [ppPStr SLIT("Failed in reading file: "), ppStr file, ppStr "; error=", ppStr (show err)]
 \end{code}