[project @ 2005-02-14 13:27:52 by simonmar]
[ghc-hetmet.git] / ghc / compiler / iface / MkIface.lhs
index 235cf2a..354e31e 100644 (file)
@@ -4,7 +4,7 @@
 
 \begin{code}
 module MkIface ( 
-       showIface,      -- Print the iface in Foo.hi
+       pprModIface, showIface,         -- Print the iface in Foo.hi
 
        mkUsageInfo,    -- Construct the usage info for a module
 
@@ -174,60 +174,69 @@ compiled with -O.  I think this is the case.]
 #include "HsVersions.h"
 
 import HsSyn
+import Packages                ( isHomeModule, PackageIdH(..) )
 import IfaceSyn                ( IfaceDecl(..), IfaceClassOp(..), IfaceConDecl(..),
                          IfaceRule(..), IfaceInst(..), IfaceExtName(..), IfaceTyCon(..),
                          eqIfDecl, eqIfRule, eqIfInst, IfaceEq(..), (&&&), bool, 
-                         eqMaybeBy, eqListBy,
+                         eqMaybeBy, eqListBy, visibleIfConDecls,
                          tyThingToIfaceDecl, dfunToIfaceInst, coreRuleToIfaceRule )
 import LoadIface       ( readIface, loadInterface, ifaceInstGates )
 import BasicTypes      ( Version, initialVersion, bumpVersion )
 import TcRnMonad
-import TcRnTypes       ( ImportAvails(..), mkModDeps )
-import HscTypes                ( ModIface(..), 
+import TcRnTypes       ( mkModDeps )
+import TcType          ( isFFITy )
+import HscTypes                ( ModIface(..), TyThing(..), 
                          ModGuts(..), ModGuts, IfaceExport,
-                         GhciMode(..), 
-                         HscEnv(..), hscEPS,
+                         GhciMode(..), HscEnv(..), hscEPS,
                          Dependencies(..), FixItem(..), 
-                         isImplicitTyThing, 
+                         ModSummary(..), msHiFilePath, 
                          mkIfaceDepCache, mkIfaceFixCache, mkIfaceVerCache,
                          typeEnvElts, 
-                         Avails, AvailInfo, GenAvailInfo(..), availName, 
+                         GenAvailInfo(..), availName, 
                          ExternalPackageState(..),
                          Usage(..), IsBootInterface,
                          Deprecs(..), IfaceDeprecs, Deprecations,
-                         lookupIfaceByModName
+                         lookupIfaceByModule
                        )
 
 
 import CmdLineOpts
-import Name            ( Name, nameModule, nameOccName, nameParent, isExternalName,
-                         nameParent_maybe, isWiredInName, NamedThing(..) )
+import Name            ( Name, nameModule, nameOccName, nameParent,
+                         isExternalName, nameParent_maybe, isWiredInName,
+                         NamedThing(..) )
 import NameEnv
 import NameSet
-import OccName         ( OccName, OccEnv, mkOccEnv, lookupOccEnv, emptyOccEnv, extendOccEnv_C,
+import OccName         ( OccName, OccEnv, mkOccEnv, lookupOccEnv, emptyOccEnv,
+                         extendOccEnv_C,
                          OccSet, emptyOccSet, elemOccSet, occSetElts, 
                          extendOccSet, extendOccSetList,
-                         isEmptyOccSet, intersectOccSet, intersectsOccSet )
-import TyCon           ( visibleDataCons )
-import Module          ( Module, ModuleName, moduleNameFS, moduleName, isHomeModule,
-                         ModLocation(..), mkSysModuleNameFS, moduleUserString,
+                         isEmptyOccSet, intersectOccSet, intersectsOccSet,
+                         occNameFS, isTcOcc )
+import TyCon           ( tyConDataCons, isNewTyCon, newTyConRep )
+import Class           ( classSelIds )
+import DataCon         ( dataConName, dataConFieldLabels )
+import Module          ( Module, moduleFS,
+                         ModLocation(..), mkSysModuleFS, moduleUserString,
                          ModuleEnv, emptyModuleEnv, lookupModuleEnv,
-                         extendModuleEnv_C, moduleEnvElts
+                         extendModuleEnv_C
                        )
 import Outputable
 import DriverUtil      ( createDirectoryHierarchy, directoryOf )
-import Util            ( sortLt, seqList )
+import Util            ( sortLe, seqList )
 import Binary          ( getBinFileWithDict )
-import BinIface                ( writeBinIface, v_IgnoreHiVersion )
+import BinIface                ( writeBinIface, v_IgnoreHiWay )
 import Unique          ( Unique, Uniquable(..) )
 import ErrUtils                ( dumpIfSet_dyn, showPass )
 import Digraph         ( stronglyConnComp, SCC(..) )
+import SrcLoc          ( SrcSpan )
 import FiniteMap
 import FastString
 
 import DATA_IOREF      ( writeIORef )
 import Monad           ( when )
-import Maybes          ( orElse, mapCatMaybes, isNothing, fromJust, expectJust )
+import List            ( insert )
+import Maybes          ( orElse, mapCatMaybes, isNothing, isJust, 
+                         fromJust, expectJust, MaybeErr(..) )
 \end{code}
 
 
@@ -244,49 +253,62 @@ mkIface :: HscEnv
        -> Maybe ModIface       -- The old interface, if we have it
        -> ModGuts              -- The compiled, tidied module
        -> IO ModIface          -- The new one, complete with decls and versions
--- mkFinalIface 
---     a) completes the interface
---     b) writes it out to a file if necessary
+-- mkIface 
+--     a) Builds the ModIface
+--     b) Writes it out to a file if necessary
 
 mkIface hsc_env location maybe_old_iface 
        guts@ModGuts{ mg_module = this_mod,
+                     mg_boot   = is_boot,
                      mg_usages = usages,
                      mg_deps   = deps,
                      mg_exports = exports,
+                     mg_rdr_env = rdr_env,
                      mg_fix_env = fix_env,
                      mg_deprecs = src_deprecs,
                      mg_insts = insts, 
                      mg_rules = rules,
                      mg_types = type_env }
   = do { eps <- hscEPS hsc_env
-       ; let   { this_mod_name = moduleName this_mod
-               ; ext_nm = mkExtNameFn hsc_env eps this_mod_name
-               ; decls  = [ tyThingToIfaceDecl omit_prags ext_nm thing 
-                          | thing <- typeEnvElts type_env
-                          , not (isImplicitTyThing thing) && not (isWiredInName (getName thing)) ]
+       ; let   { ext_nm_rhs = mkExtNameFn hsc_env eps this_mod
+               ; ext_nm_lhs = mkLhsNameFn this_mod
+               ; local_things = [thing | thing <- typeEnvElts type_env,
+                                         not (isWiredInName (getName thing)) ]
+                       -- Do not export anything about wired-in things
+                       --  (GHC knows about them already)
+
+               ; abstract_tcs :: NameSet -- TyCons and Classes whose representation is not exposed
+               ; abstract_tcs
+                   | not omit_prags = emptyNameSet             -- In the -O case, nothing is abstract
+                   | otherwise      = mkNameSet [ getName thing 
+                                                | thing <- local_things
+                                                , not (mustExposeThing exports thing)]
+
+               ; decls  = [ tyThingToIfaceDecl omit_prags abstract_tcs ext_nm_rhs thing 
+                          | thing <- local_things, wantDeclFor exports abstract_tcs thing ]
                                -- Don't put implicit Ids and class tycons in the interface file
-                               -- Nor wired-in things (GHC knows about them already)
 
                ; fixities = [(occ,fix) | FixItem occ fix _ <- nameEnvElts fix_env]
                ; deprecs  = mkIfaceDeprec src_deprecs
                ; iface_rules 
                     | omit_prags = []
-                    | otherwise  = sortLt lt_rule $
-                                   map (coreRuleToIfaceRule this_mod_name ext_nm) rules
-               ; iface_insts = sortLt lt_inst (map (dfunToIfaceInst this_mod_name) insts)
+                    | otherwise  = sortLe le_rule $
+                                   map (coreRuleToIfaceRule ext_nm_lhs ext_nm_rhs) rules
+               ; iface_insts = sortLe le_inst (map (dfunToIfaceInst ext_nm_lhs) insts)
 
                ; intermediate_iface = ModIface { 
                        mi_module   = this_mod,
-                       mi_package  = opt_InPackage,
-                       mi_boot     = False,
+                       mi_package  = HomePackage,
+                       mi_boot     = is_boot,
                        mi_deps     = deps,
                        mi_usages   = usages,
-                       mi_exports  = groupAvails this_mod exports,
+                       mi_exports  = mkIfaceExports exports,
                        mi_insts    = iface_insts,
                        mi_rules    = iface_rules,
                        mi_fixities = fixities,
                        mi_deprecs  = deprecs,
-       
+                       mi_globals  = Just rdr_env,
+
                        -- Left out deliberately: filled in by addVersionInfo
                        mi_mod_vers  = initialVersion,
                        mi_exp_vers  = initialVersion,
@@ -301,7 +323,7 @@ mkIface hsc_env location maybe_old_iface
                        mi_fix_fn = mkIfaceFixCache fixities }
 
                -- Add version information
-               ; (new_iface, no_change_at_all, pp_diffs) 
+               ; (new_iface, no_change_at_all, pp_diffs, pp_orphs) 
                        = _scc_ "versioninfo" 
                         addVersionInfo maybe_old_iface intermediate_iface decls
                }
@@ -312,56 +334,110 @@ mkIface hsc_env location maybe_old_iface
                writeBinIface hi_file_path new_iface
 
                -- Debug printing
-       ; when (dopt Opt_D_dump_hi_diffs dflags)
-              (printDump (write_diffs maybe_old_iface no_change_at_all pp_diffs))
+       ; when (isJust pp_orphs && dopt Opt_WarnOrphans dflags) 
+              (printDump (fromJust pp_orphs))
+       ; when (dopt Opt_D_dump_hi_diffs dflags) (printDump pp_diffs)
        ; dumpIfSet_dyn dflags Opt_D_dump_hi "FINAL INTERFACE" 
                        (pprModIface new_iface)
 
        ; return new_iface }
   where
-     r1 `lt_rule` r2 = ifRuleName r1 < ifRuleName r2
-     i1 `lt_inst` i2 = ifDFun     i1 < ifDFun     i2
+     r1 `le_rule` r2 = ifRuleName r1 <= ifRuleName r2
+     i1 `le_inst` i2 = ifDFun     i1 <= ifDFun     i2
 
-     dflags    = hsc_dflags hsc_env
-     ghci_mode = hsc_mode hsc_env
+     dflags              = hsc_dflags hsc_env
+     ghci_mode           = hsc_mode hsc_env
+     omit_prags   = dopt Opt_OmitInterfacePragmas dflags
      hi_file_path = ml_hi_file location
-     omit_prags = dopt Opt_OmitInterfacePragmas dflags
+
+                                             
+mustExposeThing :: NameSet -> TyThing -> Bool
+-- We are compiling without -O, and thus trying to write as little as 
+-- possible into the interface file.  But we must expose the details of
+-- any data types and classes whose constructors, fields, methods are 
+-- visible to an importing module
+mustExposeThing exports (ATyCon tc) 
+  =  any exported_data_con (tyConDataCons tc)
+       -- Expose rep if any datacon or field is exported
+
+  || (isNewTyCon tc && isFFITy (snd (newTyConRep tc)))
+       -- Expose the rep for newtypes if the rep is an FFI type.  
+       -- For a very annoying reason.  'Foreign import' is meant to
+       -- be able to look through newtypes transparently, but it
+       -- can only do that if it can "see" the newtype representation
+  where                
+     exported_data_con con 
+       = any (`elemNameSet` exports) (dataConName con : dataConFieldLabels con)
+               
+mustExposeThing exports (AClass cls) 
+  = any exported_class_op (classSelIds cls)
+  where                -- Expose rep if any classs op is exported
+     exported_class_op op = getName op `elemNameSet` exports
+
+mustExposeThing exports other = False
+
+
+wantDeclFor :: NameSet -- User-exported things
+           -> NameSet  -- Abstract things
+           -> TyThing -> Bool
+wantDeclFor exports abstracts thing
+  | Just parent <- nameParent_maybe name       -- An implicit thing
+  = parent `elemNameSet` abstracts && name `elemNameSet` exports
+  | otherwise
+  = True
+  where
+    name = getName thing
+  
 
 deliberatelyOmitted x = panic ("Deliberately omitted: " ++ x)
 
 -----------------------------
-mkExtNameFn :: HscEnv -> ExternalPackageState -> ModuleName -> Name -> IfaceExtName
+mkExtNameFn :: HscEnv -> ExternalPackageState -> Module -> Name -> IfaceExtName
 mkExtNameFn hsc_env eps this_mod
   = ext_nm
   where
+    dflags = hsc_dflags hsc_env
     hpt = hsc_HPT hsc_env
     pit = eps_PIT eps
 
     ext_nm name 
-      | mod_nm == this_mod = case nameParent_maybe name of
+      | mod == this_mod = case nameParent_maybe name of
                                Nothing  -> LocalTop occ
                                Just par -> LocalTopSub occ (nameOccName par)
-      | isWiredInName name = ExtPkg  mod_nm occ
-      | isHomeModule mod   = HomePkg mod_nm occ vers
-      | otherwise         = ExtPkg  mod_nm occ
+      | isWiredInName name       = ExtPkg  mod occ
+      | isHomeModule dflags mod  = HomePkg mod occ vers
+      | otherwise               = ExtPkg  mod occ
       where
        mod      = nameModule name
-       mod_nm   = moduleName mod
        occ      = nameOccName name
        par_occ  = nameOccName (nameParent name)
                -- The version of the *parent* is the one want
-       vers     = lookupVersion mod_nm par_occ
+       vers     = lookupVersion mod par_occ
              
-    lookupVersion :: ModuleName -> OccName -> Version
+    lookupVersion :: Module -> OccName -> Version
        -- Even though we're looking up a home-package thing, in
        -- one-shot mode the imported interfaces may be in the PIT
     lookupVersion mod occ
       = mi_ver_fn iface occ `orElse` 
         pprPanic "lookupVers1" (ppr mod <+> ppr occ)
       where
-        iface = lookupIfaceByModName hpt pit mod `orElse` 
+        iface = lookupIfaceByModule hpt pit mod `orElse` 
                pprPanic "lookupVers2" (ppr mod <+> ppr occ)
 
+
+---------------------
+-- mkLhsNameFn ignores versioning info altogether
+-- It is used for the LHS of instance decls and rules, where we 
+-- there's no point in recording version info
+mkLhsNameFn :: Module -> Name -> IfaceExtName
+mkLhsNameFn this_mod name      
+  | mod == this_mod = LocalTop occ
+  | otherwise      = ExtPkg mod occ
+  where
+    mod = nameModule name
+    occ        = nameOccName name
+
+
 -----------------------------
 -- Compute version numbers for local decls
 
@@ -370,7 +446,8 @@ addVersionInfo :: Maybe ModIface    -- The old interface, read from M.hi
               -> [IfaceDecl]           -- The new decls
               -> (ModIface, 
                   Bool,                -- True <=> no changes at all; no need to write new Iface
-                  SDoc)                -- Differences
+                  SDoc,                -- Differences
+                  Maybe SDoc)          -- Warnings about orphans
 
 addVersionInfo Nothing new_iface new_decls
 -- No old interface, so definitely write a new one!
@@ -378,7 +455,12 @@ addVersionInfo Nothing new_iface new_decls
                          || anyNothing getRuleKey (mi_rules new_iface),
                 mi_decls  = [(initialVersion, decl) | decl <- new_decls],
                 mi_ver_fn = \n -> Just initialVersion },
-     False, text "No old interface available")
+     False, 
+     ptext SLIT("No old interface file"),
+     pprOrphans orph_insts orph_rules)
+  where
+    orph_insts = filter (isNothing . getInstKey) (mi_insts new_iface)
+    orph_rules = filter (isNothing . getRuleKey) (mi_rules new_iface)
 
 addVersionInfo (Just old_iface@(ModIface { mi_mod_vers  = old_mod_vers, 
                                           mi_exp_vers  = old_exp_vers, 
@@ -389,8 +471,9 @@ addVersionInfo (Just old_iface@(ModIface { mi_mod_vers  = old_mod_vers,
               new_iface@(ModIface { mi_fix_fn = new_fixities })
               new_decls
 
-  | no_change_at_all = (old_iface, True, empty)
-  | otherwise       = (final_iface, False, pp_diffs)
+  | no_change_at_all = (old_iface,   True,  ptext SLIT("Interface file unchanged"), pp_orphs)
+  | otherwise       = (final_iface, False, vcat [ptext SLIT("Interface file has changed"),
+                                                 nest 2 pp_diffs], pp_orphs)
   where
     final_iface = new_iface { mi_mod_vers  = bump_unless no_output_change old_mod_vers,
                              mi_exp_vers  = bump_unless no_export_change old_exp_vers,
@@ -402,8 +485,8 @@ addVersionInfo (Just old_iface@(ModIface { mi_mod_vers  = old_mod_vers,
     decls_w_vers = [(add_vers decl, decl) | decl <- new_decls]
 
     -------------------
-    (new_non_orph_insts, new_orph_insts) = mkRuleMap getInstKey (mi_insts new_iface)
     (old_non_orph_insts, old_orph_insts) = mkRuleMap getInstKey (mi_insts old_iface)
+    (new_non_orph_insts, new_orph_insts) = mkRuleMap getInstKey (mi_insts new_iface)
     same_insts occ = eqMaybeBy (eqListBy eqIfInst) 
                                (lookupOccEnv old_non_orph_insts occ)
                                (lookupOccEnv new_non_orph_insts occ)
@@ -424,17 +507,17 @@ addVersionInfo (Just old_iface@(ModIface { mi_mod_vers  = old_mod_vers,
     no_deprec_change = mi_deprecs new_iface == mi_deprecs old_iface
 
        -- If the usages havn't changed either, we don't need to write the interface file
-       -- Question: should we also check for equality of mi_deps?
-    no_other_changes = mi_usages new_iface == mi_usages old_iface
+    no_other_changes = mi_usages new_iface == mi_usages old_iface && 
+                      mi_deps new_iface == mi_deps old_iface
     no_change_at_all = no_output_change && no_other_changes
  
-    pp_diffs = vcat [pp_decl_diffs,
-                    pp_change no_export_change "Export list" 
+    pp_diffs = vcat [pp_change no_export_change "Export list" 
                        (ppr old_exp_vers <+> arrow <+> ppr (mi_exp_vers final_iface)),
                     pp_change no_rule_change "Rules"
                        (ppr old_rule_vers <+> arrow <+> ppr (mi_rule_vers final_iface)),
                     pp_change no_deprec_change "Deprecations" empty,
-                    pp_change no_other_changes  "Usages" empty]
+                    pp_change no_other_changes  "Usages" empty,
+                    pp_decl_diffs]
     pp_change True  what info = empty
     pp_change False what info = text what <+> ptext SLIT("changed") <+> info
 
@@ -474,7 +557,7 @@ addVersionInfo (Just old_iface@(ModIface { mi_mod_vers  = old_mod_vers,
          eq_ind_occs [op | IfaceClassOp op _ _ <- sigs] 
     eq_indirects (IfaceData {ifName = tc_occ, ifCons = cons})
        = same_insts tc_occ &&& same_fixity tc_occ &&&  -- The TyCon can have a fixity too
-         eq_ind_occs [occ | IfaceConDecl occ _ _ _ _ _ <- visibleDataCons cons]
+         eq_ind_occs (map ifConOcc (visibleIfConDecls cons))
     eq_indirects other = Equal -- Synonyms and foreign declarations
 
     eq_ind_occ :: OccName -> IfaceEq   -- For class ops and Ids; check fixity and rules
@@ -511,6 +594,19 @@ addVersionInfo (Just old_iface@(ModIface { mi_mod_vers  = old_mod_vers,
                        -> ppr occ <+> ptext SLIT("only in new interface")
                    other -> pprPanic "MkIface.show_change" (ppr occ)
        
+    pp_orphs = pprOrphans new_orph_insts new_orph_rules
+
+pprOrphans insts rules
+  | null insts && null rules = Nothing
+  | otherwise
+  = Just $ vcat [
+       if null insts then empty else
+            hang (ptext SLIT("Warning: orphan instances:"))
+               2 (vcat (map ppr insts)),
+       if null rules then empty else
+            hang (ptext SLIT("Warning: orphan rules:"))
+               2 (vcat (map ppr rules))
+    ]
 
 computeChangedOccs :: [(OccName, IfaceEq)] -> OccSet
 computeChangedOccs eq_info
@@ -581,13 +677,7 @@ anyNothing p (x:xs) = isNothing (p x) || anyNothing p xs
 mkIfaceDeprec :: Deprecations -> IfaceDeprecs
 mkIfaceDeprec NoDeprecs        = NoDeprecs
 mkIfaceDeprec (DeprecAll t)    = DeprecAll t
-mkIfaceDeprec (DeprecSome env) = DeprecSome (sortLt (<) (nameEnvElts env))
-
-----------------------
-write_diffs :: Maybe ModIface -> Bool -> SDoc -> SDoc
-write_diffs Nothing  _     _     = ptext SLIT("NO OLD INTERFACE FILE")
-write_diffs (Just _) True  _     = ptext SLIT("INTERFACE UNCHANGED")
-write_diffs (Just _) False diffs = sep [ptext SLIT("INTERFACE HAS CHANGED"), nest 2 diffs]
+mkIfaceDeprec (DeprecSome env) = DeprecSome (sortLe (<=) (nameEnvElts env))
 
 ----------------------
 bump_unless :: Bool -> Version -> Version
@@ -604,21 +694,26 @@ bump_unless False v = bumpVersion v
 
 
 \begin{code}
-mkUsageInfo :: HscEnv -> ImportAvails -> NameSet -> IO [Usage]
-mkUsageInfo hsc_env
-           (ImportAvails { imp_mods = dir_imp_mods,
-                           imp_dep_mods = dep_mods })
-           used_names
+mkUsageInfo :: HscEnv 
+           -> ModuleEnv (Module, Maybe Bool, SrcSpan)
+           -> [(Module, IsBootInterface)]
+           -> NameSet -> IO [Usage]
+mkUsageInfo hsc_env dir_imp_mods dep_mods used_names
   = do { eps <- hscEPS hsc_env
-       ; return (mk_usage_info (eps_PIT eps) (hsc_HPT hsc_env) 
-                               dir_imp_mods dep_mods used_names) }
-
-mk_usage_info pit hpt dir_imp_mods dep_mods proto_used_names
-  = -- seq the list of Usages returned: occasionally these
-    -- don't get evaluated for a while and we can end up hanging on to
-    -- the entire collection of Ifaces.
-    usages `seqList` usages
+       ; let usages = mk_usage_info (eps_PIT eps) hsc_env
+                                    dir_imp_mods dep_mods used_names
+       ; usages `seqList`  return usages }
+        -- seq the list of Usages returned: occasionally these
+        -- don't get evaluated for a while and we can end up hanging on to
+        -- the entire collection of Ifaces.
+
+mk_usage_info pit hsc_env dir_imp_mods dep_mods proto_used_names
+  = mapCatMaybes mkUsage dep_mods
+       -- ToDo: do we need to sort into canonical order?
   where
+    dflags = hsc_dflags hsc_env
+    hpt = hsc_HPT hsc_env
+
     used_names = mkNameSet $                   -- Eliminate duplicates
                 [ nameParent n                 -- Just record usage on the 'main' names
                 | n <- nameSetToList proto_used_names
@@ -636,12 +731,9 @@ mk_usage_info pit hpt dir_imp_mods dep_mods proto_used_names
                     mod = nameModule name
                     add_item occs _ = occ:occs
     
-    usages = mapCatMaybes mkUsage (moduleEnvElts dep_mods)
-       -- ToDo: do we need to sort into canonical order?
-
     import_all mod = case lookupModuleEnv dir_imp_mods mod of
-                       Just (_,imp_all) -> isNothing imp_all
-                       Nothing          -> False
+                       Just (_,imp_all,_) -> isNothing imp_all
+                       Nothing            -> False
     
     -- We want to create a Usage for a home module if 
     -- a) we used something from; has something in used_names
@@ -649,23 +741,23 @@ mk_usage_info pit hpt dir_imp_mods dep_mods proto_used_names
     --         (need to recompile if its export list changes: export_vers)
     -- c) is a home-package orphan module (need to recompile if its
     --         instance decls change: rules_vers)
-    mkUsage :: (ModuleName, Bool) -> Maybe Usage
+    mkUsage :: (Module, Bool) -> Maybe Usage
     mkUsage (mod_name, _)
       |  isNothing maybe_iface -- We can't depend on it if we didn't
-      || not (isHomeModule mod)        -- even open the interface!
+      || not (isHomeModule dflags mod) -- even open the interface!
       || (null used_occs
          && not all_imported
          && not orphan_mod)
       = Nothing                        -- Record no usage info
     
       | otherwise      
-      = Just (Usage { usg_name     = moduleName mod,
+      = Just (Usage { usg_name     = mod,
                      usg_mod      = mod_vers,
                      usg_exports  = export_vers,
                      usg_entities = ent_vers,
                      usg_rules    = rules_vers })
       where
-       maybe_iface  = lookupIfaceByModName hpt pit mod_name
+       maybe_iface  = lookupIfaceByModule hpt pit mod_name
                -- In one-shot mode, the interfaces for home-package 
                -- modules accumulate in the PIT not HPT.  Sigh.
 
@@ -683,44 +775,39 @@ mk_usage_info pit hpt dir_imp_mods dep_mods proto_used_names
         used_occs = lookupModuleEnv ent_map mod `orElse` []
        ent_vers :: [(OccName,Version)]
         ent_vers = [ (occ, version_env occ `orElse` initialVersion) 
-                  | occ <- sortLt (<) used_occs]
+                  | occ <- sortLe (<=) used_occs]
 \end{code}
 
 \begin{code}
-groupAvails :: Module -> Avails -> [(ModuleName, [GenAvailInfo OccName])]
+mkIfaceExports :: NameSet -> [(Module, [GenAvailInfo OccName])]
   -- Group by module and sort by occurrence
   -- This keeps the list in canonical order
-groupAvails this_mod avails 
-  = [ (mkSysModuleNameFS fs, sortLt lt avails)
-    | (fs,avails) <- fmToList groupFM
+mkIfaceExports exports 
+  = [ (mkSysModuleFS fs, eltsFM avails)
+    | (fs, avails) <- fmToList groupFM
     ]
   where
-    groupFM :: FiniteMap FastString [GenAvailInfo OccName]
+    groupFM :: FiniteMap FastString (FiniteMap FastString (GenAvailInfo OccName))
        -- Deliberately use the FastString so we
        -- get a canonical ordering
-    groupFM = foldl add emptyFM avails
+    groupFM = foldl add emptyFM (nameSetToList exports)
 
-    add env avail = addToFM_C (\old _ -> avail':old) env mod_fs [avail']
-                 where
-                   mod_fs    = moduleNameFS (moduleName avail_mod)
-                   avail_mod = nameModule (availName avail)
-                   avail'    = sortAvail avail
-
-    a1 `lt` a2 = availName a1 < availName a2
-
-sortAvail :: AvailInfo -> GenAvailInfo OccName
--- Convert to OccName, and sort the sub-names into canonical order
--- The canonical order has the "main name" at the beginning 
--- (if it's there at all)
-sortAvail (Avail n) = Avail (nameOccName n)
-sortAvail (AvailTC n ns) 
-  | n `elem` ns = AvailTC occ (occ : mk_occs (filter (/= n) ns))
-  | otherwise   = AvailTC occ (      mk_occs ns)
-  where
-    occ = nameOccName n
-    mk_occs ns = sortLt (<) (map nameOccName ns)
+    add env name = addToFM_C add_avail env mod_fs 
+                            (unitFM avail_fs avail)
+      where
+       occ    = nameOccName name
+       mod_fs = moduleFS (nameModule name)
+       avail | Just p <- nameParent_maybe name = AvailTC (nameOccName p) [occ]
+             | isTcOcc occ                     = AvailTC occ [occ]
+             | otherwise                       = Avail occ
+       avail_fs = occNameFS (availName avail)      
+       add_avail avail_fm _ = addToFM_C add_item avail_fm avail_fs avail
+
+       add_item (AvailTC p occs) _ = AvailTC p (List.insert occ occs)
+       add_item (Avail n)        _ = pprPanic "MkIface.addAvail" (ppr n <+> ppr name)
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
        Load the old interface file for this module (unless
@@ -731,21 +818,20 @@ sortAvail (AvailTC n ns)
 
 \begin{code}
 checkOldIface :: HscEnv
-             -> Module
-             -> FilePath               -- Where the interface file is
+             -> ModSummary
              -> Bool                   -- Source unchanged
              -> Maybe ModIface         -- Old interface from compilation manager, if any
              -> IO (RecompileRequired, Maybe ModIface)
 
-checkOldIface hsc_env mod iface_path source_unchanged maybe_iface
+checkOldIface hsc_env mod_summary source_unchanged maybe_iface
   = do { showPass (hsc_dflags hsc_env) 
-                  ("Checking old interface for " ++ moduleUserString mod) ;
+                  ("Checking old interface for " ++ moduleUserString (ms_mod mod_summary)) ;
 
        ; initIfaceCheck hsc_env $
-         check_old_iface mod iface_path source_unchanged maybe_iface
+         check_old_iface mod_summary source_unchanged maybe_iface
      }
 
-check_old_iface this_mod iface_path source_unchanged maybe_iface
+check_old_iface mod_summary source_unchanged maybe_iface
  =     -- CHECK WHETHER THE SOURCE HAS CHANGED
     ifM (not source_unchanged)
        (traceHiDiffs (nest 4 (text "Source file changed or recompilation check turned off")))
@@ -767,14 +853,17 @@ check_old_iface this_mod iface_path source_unchanged maybe_iface
 
        -- Try and read the old interface for the current module
        -- from the .hi file left from the last time we compiled it
-    readIface (moduleName this_mod) iface_path False           `thenM` \ read_result ->
+    let
+       iface_path = msHiFilePath mod_summary
+    in
+    readIface (ms_mod mod_summary) iface_path False    `thenM` \ read_result ->
     case read_result of {
-       Left err ->     -- Old interface file not found, or garbled; give up
-                  traceHiDiffs (text "FYI: cannot read old interface file:"
+       Failed err ->   -- Old interface file not found, or garbled; give up
+                  traceIf (text "FYI: cannot read old interface file:"
                                 $$ nest 4 err)         `thenM_`
                   returnM (outOfDate, Nothing)
 
-    ;  Right iface ->  
+    ;  Succeeded iface ->      
 
        -- We have got the old iface; check its versions
     checkVersions source_unchanged iface       `thenM` \ recomp ->
@@ -799,21 +888,26 @@ checkVersions source_unchanged iface
   | not source_unchanged
   = returnM outOfDate
   | otherwise
-  = traceHiDiffs (text "Considering whether compilation is required for" <+> 
-                 ppr (mi_module iface) <> colon)       `thenM_`
+  = do { traceHiDiffs (text "Considering whether compilation is required for" <+> 
+                       ppr (mi_module iface) <> colon)
 
        -- Source code unchanged and no errors yet... carry on 
-       -- First put the dependent-module info in the envt, just temporarily,
+
+       -- First put the dependent-module info, read from the old interface, into the envt, 
        -- so that when we look for interfaces we look for the right one (.hi or .hi-boot)
+       -- 
        -- It's just temporary because either the usage check will succeed 
        -- (in which case we are done with this module) or it'll fail (in which
        -- case we'll compile the module from scratch anyhow).
-    updGblEnv (\ gbl -> gbl { if_is_boot = mod_deps }) (
-       checkList [checkModUsage u | u <- mi_usages iface]
-    )
+       --      
+       -- We do this regardless of compilation mode
+       ; updateEps_ $ \eps  -> eps { eps_is_boot = mod_deps }
+
+       ; checkList [checkModUsage u | u <- mi_usages iface]
+    }
   where
        -- This is a bit of a hack really
-    mod_deps :: ModuleEnv (ModuleName, IsBootInterface)
+    mod_deps :: ModuleEnv (Module, IsBootInterface)
     mod_deps = mkModDeps (dep_mods (mi_deps iface))
 
 checkModUsage :: Usage -> IfG RecompileRequired
@@ -836,13 +930,13 @@ checkModUsage (Usage { usg_name = mod_name, usg_mod = old_mod_vers,
        -- Instead, get an Either back which we can test
 
     case mb_iface of {
-       Left exn ->  (out_of_date (sep [ptext SLIT("Can't find version number for module"), 
+       Failed exn ->  (out_of_date (sep [ptext SLIT("Can't find version number for module"), 
                                       ppr mod_name]));
                -- Couldn't find or parse a module mentioned in the
                -- old interface file.  Don't complain -- it might just be that
                -- the current module doesn't need that import and it's been deleted
 
-       Right iface -> 
+       Succeeded iface -> 
     let
        new_mod_vers    = mi_mod_vers  iface
        new_decl_vers   = mi_ver_fn    iface
@@ -930,7 +1024,7 @@ showIface :: FilePath -> IO ()
 showIface filename = do
    -- skip the version check; we don't want to worry about profiled vs.
    -- non-profiled interfaces, for example.
-   writeIORef v_IgnoreHiVersion True
+   writeIORef v_IgnoreHiWay True
    iface <- Binary.getBinFileWithDict filename
    printDump (pprModIface iface)
  where
@@ -942,10 +1036,10 @@ pprModIface :: ModIface -> SDoc
 -- Show a ModIface
 pprModIface iface
  = vcat [ ptext SLIT("interface")
-               <+> doubleQuotes (ftext (mi_package iface))
-               <+> ppr (mi_module iface) <+> ppr (mi_mod_vers iface)
-               <+> pp_sub_vers
-               <+> (if mi_orphan iface then char '!' else empty)
+               <+> ppr_package (mi_package iface)
+               <+> ppr (mi_module iface) <+> pp_boot 
+               <+> ppr (mi_mod_vers iface) <+> pp_sub_vers
+               <+> (if mi_orphan iface then ptext SLIT("[orphan module]") else empty)
                <+> int opt_HiVersion
                <+> ptext SLIT("where")
        , vcat (map pprExport (mi_exports iface))
@@ -958,6 +1052,11 @@ pprModIface iface
        , pprDeprecs (mi_deprecs iface)
        ]
   where
+    pp_boot | mi_boot iface = ptext SLIT("[boot]")
+           | otherwise     = empty
+    ppr_package HomePackage = empty
+    ppr_package (ExtPackage id) = doubleQuotes (ppr id)
+
     exp_vers  = mi_exp_vers iface
     rule_vers = mi_rule_vers iface