Interface file optimisation and removal of nameParent
[ghc-hetmet.git] / compiler / iface / LoadIface.lhs
index 3faf00c..5b19c89 100644 (file)
@@ -1,4 +1,4 @@
-%
+
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 \section{Dealing with interface files}
@@ -8,19 +8,23 @@ module LoadIface (
        loadInterface, loadInterfaceForName, loadWiredInHomeIface, 
        loadSrcInterface, loadSysInterface, loadOrphanModules, 
        findAndReadIface, readIface,    -- Used when reading the module's old interface
-       loadDecls, ifaceStats, discardDeclPrags,
-       initExternalPackageState
+       loadDecls,      -- Should move to TcIface and be renamed
+       initExternalPackageState,
+
+       ifaceStats, pprModIface, showIface
    ) where
 
 #include "HsVersions.h"
 
-import {-# SOURCE #-}  TcIface( tcIfaceDecl, tcIfaceRule, tcIfaceInst )
+import {-# SOURCE #-}  TcIface( tcIfaceDecl, tcIfaceRules, tcIfaceInst, 
+                                tcIfaceFamInst )
 
 import DynFlags                ( DynFlags(..), DynFlag( Opt_IgnoreInterfacePragmas ) )
-import IfaceSyn                ( IfaceDecl(..), IfaceConDecl(..), IfaceClassOp(..),
-                         IfaceConDecls(..), IfaceIdInfo(..) )
+import IfaceSyn
 import IfaceEnv                ( newGlobalBinder )
-import HscTypes                ( ModIface(..), TyThing, emptyModIface, EpsStats(..),
+import HscTypes                ( ModIface(..), TyThing, IfaceExport, Usage(..), 
+                         Deprecs(..), Dependencies(..),
+                         emptyModIface, EpsStats(..), GenAvailInfo(..),
                          addEpsInStats, ExternalPackageState(..),
                          PackageTypeEnv, emptyTypeEnv,  HscEnv(..),
                          lookupIfaceByModule, emptyPackageIfaceTable,
@@ -28,33 +32,40 @@ import HscTypes             ( ModIface(..), TyThing, emptyModIface, EpsStats(..),
                          implicitTyThings 
                         )
 
-import BasicTypes      ( Version, Fixity(..), FixityDirection(..),
-                         isMarkedStrict )
+import BasicTypes      ( Version, initialVersion,
+                         Fixity(..), FixityDirection(..), isMarkedStrict )
 import TcRnMonad
+import Type             ( TyThing(..) )
 
 import PrelNames       ( gHC_PRIM )
 import PrelInfo                ( ghcPrimExports )
 import PrelRules       ( builtinRules )
 import Rules           ( extendRuleBaseList, mkRuleBase )
 import InstEnv         ( emptyInstEnv, extendInstEnvList )
+import FamInstEnv      ( emptyFamInstEnv, extendFamInstEnvList )
 import Name            ( Name {-instance NamedThing-}, getOccName,
                          nameModule, nameIsLocalOrFrom, isWiredInName )
 import NameEnv
 import MkId            ( seqId )
 import Module
 import OccName         ( OccName, mkOccEnv, lookupOccEnv, mkClassTyConOcc,
-                          mkClassDataConOcc, mkSuperDictSelOcc, 
-                          mkDataConWrapperOcc, mkDataConWorkerOcc )
+                         mkClassDataConOcc, mkSuperDictSelOcc,
+                         mkDataConWrapperOcc, mkDataConWorkerOcc,
+                         mkNewTyCoOcc, mkInstTyCoOcc ) 
 import SrcLoc          ( importedSrcLoc )
 import Maybes          ( MaybeErr(..) )
 import ErrUtils         ( Message )
 import Finder          ( findImportedModule, findExactModule,  
                          FindResult(..), cannotFindInterface )
 import UniqFM
+import StaticFlags     ( opt_HiVersion )
 import Outputable
-import BinIface                ( readBinIface )
-import Panic           ( ghcError, tryMost, showException, GhcException(..) )
+import BinIface                ( readBinIface, v_IgnoreHiWay )
+import Binary
+import Panic           ( ghcError, showException, GhcException(..) )
 import List            ( nub )
+import Maybe            ( isJust )
+import DATA_IOREF      ( writeIORef )
 \end{code}
 
 
@@ -146,6 +157,9 @@ loadSysInterface doc mod_name
 loadInterface :: SDoc -> Module -> WhereFrom
              -> IfM lcl (MaybeErr Message ModIface)
 
+-- loadInterface looks in both the HPT and PIT for the required interface
+-- If not found, it loads it, and puts it in the PIT (always). 
+
 -- If it can't find a suitable interface file, we
 --     a) modify the PackageIfaceTable to have an empty entry
 --             (to avoid repeated complaints)
@@ -184,7 +198,6 @@ loadInterface doc_str mod from
 
        -- READ THE MODULE IN
        ; read_result <- findAndReadIface doc_str mod hi_boot_file
-       ; dflags <- getDOpts
        ; case read_result of {
            Failed err -> do
                { let fake_iface = emptyModIface mod
@@ -197,7 +210,7 @@ loadInterface doc_str mod from
                ; returnM (Failed err) } ;
 
        -- Found and parsed!
-           Succeeded (iface, file_path)                        -- Sanity check:
+           Succeeded (iface, file_path)        -- Sanity check:
                | ImportBySystem <- from,       --   system-importing...
                  modulePackageId (mi_module iface) == thisPackage dflags,
                                                --   a home-package module...
@@ -227,32 +240,37 @@ loadInterface doc_str mod from
        --     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)
 
-       ; ignore_prags <- doptM Opt_IgnoreInterfacePragmas
-       ; new_eps_decls <- loadDecls ignore_prags (mi_decls iface)
-       ; new_eps_insts <- mapM tcIfaceInst (mi_insts iface)
-       ; new_eps_rules <- if ignore_prags 
-                          then return []
-                          else mapM tcIfaceRule (mi_rules iface)
+       ; ignore_prags      <- doptM Opt_IgnoreInterfacePragmas
+       ; new_eps_decls     <- loadDecls ignore_prags (mi_decls iface)
+       ; 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)
 
        ; let { final_iface = iface {   mi_decls = panic "No mi_decls in PIT",
                                        mi_insts = panic "No mi_insts in PIT",
                                        mi_rules = panic "No mi_rules in PIT" } }
 
        ; updateEps_  $ \ eps -> 
-           eps { eps_PIT       = extendModuleEnv (eps_PIT eps) mod final_iface,
-                 eps_PTE       = addDeclsToPTE   (eps_PTE eps) new_eps_decls,
-                 eps_rule_base = extendRuleBaseList (eps_rule_base eps) new_eps_rules,
-                 eps_inst_env  = extendInstEnvList  (eps_inst_env eps)  new_eps_insts,
-                 eps_stats     = addEpsInStats (eps_stats eps) (length new_eps_decls)
-                                               (length new_eps_insts) (length new_eps_rules) }
+           eps { 
+             eps_PIT          = extendModuleEnv (eps_PIT eps) mod final_iface,
+             eps_PTE          = addDeclsToPTE   (eps_PTE eps) new_eps_decls,
+             eps_rule_base    = extendRuleBaseList (eps_rule_base eps) 
+                                                   new_eps_rules,
+             eps_inst_env     = extendInstEnvList (eps_inst_env eps)  
+                                                  new_eps_insts,
+             eps_fam_inst_env = extendFamInstEnvList (eps_fam_inst_env eps)
+                                                     new_eps_fam_insts,
+             eps_stats        = addEpsInStats (eps_stats eps) 
+                                              (length new_eps_decls)
+             (length new_eps_insts) (length new_eps_rules) }
 
        ; return (Succeeded final_iface)
     }}}}
 
 badDepMsg mod 
   = hang (ptext SLIT("Interface file inconsistency:"))
-       2 (sep [ptext SLIT("home-package module") <+> quotes (ppr mod) <+> ptext SLIT("is mentioned,"), 
-              ptext SLIT("but does not appear in the dependencies of the interface")])
+       2 (sep [ptext SLIT("home-package module") <+> quotes (ppr mod) <+> ptext SLIT("is mentioned is needed,"), 
+              ptext SLIT("but is not among the dependencies of interfaces directly imported by the module being compiled")])
 
 -----------------------------------------------------
 --     Loading type/class/value decls
@@ -261,6 +279,10 @@ badDepMsg mod
 -- each binder with the right package info in it
 -- All subsequent lookups, including crucially lookups during typechecking
 -- the declaration itself, will find the fully-glorious Name
+--
+-- We handle ATs specially.  They are not main declarations, but also not
+-- implict things (in particular, adding them to `implicitTyThings' would mess
+-- things up in the renaming/type checking of source programs).
 -----------------------------------------------------
 
 addDeclsToPTE :: PackageTypeEnv -> [(Name,TyThing)] -> PackageTypeEnv
@@ -275,52 +297,55 @@ loadDecls ignore_prags ver_decls
        ; return (concat thingss)
        }
 
-loadDecl :: Bool                       -- Don't load pragmas into the decl pool
+loadDecl :: Bool                   -- Don't load pragmas into the decl pool
         -> Module
          -> (Version, IfaceDecl)
-         -> IfL [(Name,TyThing)]       -- The list can be poked eagerly, but the
-                                       -- TyThings are forkM'd thunks
+         -> IfL [(Name,TyThing)]   -- The list can be poked eagerly, but the
+                                   -- TyThings are forkM'd thunks
 loadDecl ignore_prags mod (_version, decl)
   = do         {       -- Populate the name cache with final versions of all 
                -- the names associated with the decl
-         main_name      <- mk_new_bndr mod Nothing (ifName decl)
-       ; implicit_names <- mapM (mk_new_bndr mod (Just main_name)) (ifaceDeclSubBndrs decl)
+         main_name      <- mk_new_bndr mod (ifName decl)
+        ; traceIf (text "Loading decl for " <> ppr main_name)
+       ; implicit_names <- mapM (mk_new_bndr mod) (ifaceDeclSubBndrs decl)
 
        -- Typecheck the thing, lazily
-       -- NB. firstly, the laziness is there in case we never need the
+       -- NB. Firstly, the laziness is there in case we never need the
        -- declaration (in one-shot mode), and secondly it is there so that 
        -- we don't look up the occurrence of a name before calling mk_new_bndr
        -- on the binder.  This is important because we must get the right name
        -- which includes its nameParent.
-       ; thing <- forkM doc (bumpDeclStats main_name >> tcIfaceDecl stripped_decl)
+
+       ; thing <- forkM doc $ do { bumpDeclStats main_name
+                                 ; tcIfaceDecl ignore_prags decl }
+
+       -- Populate the type environment with the implicitTyThings too
        ; let mini_env = mkOccEnv [(getOccName t, t) | t <- implicitTyThings thing]
              lookup n = case lookupOccEnv mini_env (getOccName n) of
                           Just thing -> thing
-                          Nothing    -> pprPanic "loadDecl" (ppr main_name <+> ppr n)
+                          Nothing    -> 
+                            pprPanic "loadDecl" (ppr main_name <+> ppr n $$ ppr (decl))
 
-       ; returnM ((main_name, thing) : [(n, lookup n) | n <- implicit_names]) }
+       ; returnM $ (main_name, thing) :  [(n, lookup n) | n <- implicit_names]
+       }
                -- We build a list from the *known* names, with (lookup n) thunks
                -- as the TyThings.  That way we can extend the PTE without poking the
                -- thunks
   where
-    stripped_decl | ignore_prags = discardDeclPrags decl
-                 | otherwise    = decl
-
        -- mk_new_bndr allocates in the name cache the final canonical
        -- name for the thing, with the correct 
        --      * parent
        --      * location
        -- imported name, to fix the module correctly in the cache
-    mk_new_bndr mod mb_parent occ 
-       = newGlobalBinder mod occ mb_parent 
+    mk_new_bndr mod occ 
+       = newGlobalBinder mod occ 
                          (importedSrcLoc (showSDoc (ppr (moduleName mod))))
                        -- ToDo: qualify with the package name if necessary
 
-    doc = ptext SLIT("Declaration for") <+> ppr (ifName decl)
+    ifFamily (IfaceData {ifFamInst = Just (famTyCon, _)}) = Just famTyCon
+    ifFamily _                                           = Nothing
 
-discardDeclPrags :: IfaceDecl -> IfaceDecl
-discardDeclPrags decl@(IfaceId {ifIdInfo = HasInfo _}) = decl { ifIdInfo = NoInfo }
-discardDeclPrags decl                                 = decl
+    doc = ptext SLIT("Declaration for") <+> ppr (ifName decl)
 
 bumpDeclStats :: Name -> IfL ()                -- Record that one more declaration has actually been used
 bumpDeclStats name
@@ -328,59 +353,6 @@ bumpDeclStats name
        ; updateEps_ (\eps -> let stats = eps_stats eps
                              in eps { eps_stats = stats { n_decls_out = n_decls_out stats + 1 } })
        }
-
------------------
-ifaceDeclSubBndrs :: IfaceDecl -> [OccName]
---  *Excludes* the 'main' name, but *includes* the implicitly-bound names
--- Deeply revolting, because it has to predict what gets bound,
--- especially the question of whether there's a wrapper for a datacon
-
-ifaceDeclSubBndrs IfaceClass { ifCtxt = sc_ctxt, 
-                               ifName = cls_occ, 
-                               ifSigs = sigs }
-  = co_occs ++
-    [tc_occ, dc_occ, dcww_occ] ++
-    [op | IfaceClassOp op _ _ <- sigs] ++
-    [mkSuperDictSelOcc n cls_occ | n <- [1..n_ctxt]] 
-  where
-    n_ctxt = length sc_ctxt
-    n_sigs = length sigs
-    tc_occ  = mkClassTyConOcc cls_occ
-    dc_occ  = mkClassDataConOcc cls_occ        
-    co_occs | is_newtype = [mkNewTyCoOcc tc_occ]
-           | otherwise  = []
-    dcww_occ | is_newtype = mkDataConWrapperOcc dc_occ -- Newtypes have wrapper but no worker
-            | otherwise  = mkDataConWorkerOcc dc_occ   -- Otherwise worker but no wrapper
-    is_newtype = n_sigs + n_ctxt == 1                  -- Sigh 
-
-ifaceDeclSubBndrs IfaceData {ifCons = IfAbstractTyCon}
-  = []
--- Newtype
-ifaceDeclSubBndrs IfaceData {ifCons = IfNewTyCon (IfVanillaCon { 
-                                                      ifConOcc = con_occ,
-                                                      ifConFields = fields})}
-  = fields ++ [con_occ, mkDataConWrapperOcc con_occ]
-       -- Wrapper, no worker; see MkId.mkDataConIds
-
-ifaceDeclSubBndrs (IfaceData {ifCons = IfDataTyCon cons})
-  = nub (concatMap fld_occs cons)      -- Eliminate duplicate fields
-    ++ concatMap dc_occs cons
-  where
-    fld_occs (IfVanillaCon { ifConFields = fields }) = fields
-    fld_occs (IfGadtCon {})                          = []
-    dc_occs con_decl
-       | has_wrapper = [con_occ, work_occ, wrap_occ]
-       | otherwise   = [con_occ, work_occ]
-       where
-         con_occ = ifConOcc con_decl
-         strs    = ifConStricts con_decl
-         wrap_occ = mkDataConWrapperOcc con_occ
-         work_occ = mkDataConWorkerOcc con_occ
-         has_wrapper = any isMarkedStrict strs -- See MkId.mkDataConIds (sigh)
-               -- ToDo: may miss strictness in existential dicts
-
-ifaceDeclSubBndrs _other                     = []
-
 \end{code}
 
 
@@ -464,8 +436,7 @@ readIface :: Module -> FilePath -> IsBootInterface
 
 readIface wanted_mod file_path is_hi_boot_file
   = do { dflags <- getDOpts
-       ; ioToIOEnv $ do
-       { res <- tryMost (readBinIface file_path)
+        ; res <- tryMostM $ readBinIface file_path
        ; case res of
            Right iface 
                | wanted_mod == actual_mod -> return (Succeeded iface)
@@ -475,7 +446,7 @@ readIface wanted_mod file_path is_hi_boot_file
                  err = hiModuleNameMismatchWarn wanted_mod actual_mod
 
            Left exn    -> return (Failed (text (showException exn)))
-    }}
+    }
 \end{code}
 
 
@@ -489,11 +460,12 @@ readIface wanted_mod file_path is_hi_boot_file
 initExternalPackageState :: ExternalPackageState
 initExternalPackageState
   = EPS { 
-      eps_is_boot    = emptyUFM,
-      eps_PIT        = emptyPackageIfaceTable,
-      eps_PTE        = emptyTypeEnv,
-      eps_inst_env   = emptyInstEnv,
-      eps_rule_base  = mkRuleBase builtinRules,
+      eps_is_boot      = emptyUFM,
+      eps_PIT          = emptyPackageIfaceTable,
+      eps_PTE          = emptyTypeEnv,
+      eps_inst_env     = emptyInstEnv,
+      eps_fam_inst_env = emptyFamInstEnv,
+      eps_rule_base    = mkRuleBase builtinRules,
        -- Initialise the EPS rule pool with the built-in rules
       eps_stats = EpsStats { n_ifaces_in = 0, n_decls_in = 0, n_decls_out = 0
                           , n_insts_in = 0, n_insts_out = 0
@@ -546,6 +518,118 @@ ifaceStats eps
 \end{code}    
 
 
+%************************************************************************
+%*                                                                     *
+               Printing interfaces
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+-- | Read binary interface, and print it out
+showIface :: HscEnv -> FilePath -> IO ()
+showIface hsc_env filename = do
+   -- skip the version check; we don't want to worry about profiled vs.
+   -- non-profiled interfaces, for example.
+   writeIORef v_IgnoreHiWay True
+   iface <- initTcRnIf 's' hsc_env () () $ readBinIface  filename
+   printDump (pprModIface iface)
+\end{code}
+
+\begin{code}
+pprModIface :: ModIface -> SDoc
+-- Show a ModIface
+pprModIface iface
+ = vcat [ ptext SLIT("interface")
+               <+> 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))
+       , pprDeps (mi_deps iface)
+       , vcat (map pprUsage (mi_usages iface))
+       , pprFixities (mi_fixities iface)
+       , vcat (map pprIfaceDecl (mi_decls iface))
+       , vcat (map ppr (mi_insts iface))
+       , vcat (map ppr (mi_rules iface))
+       , pprDeprecs (mi_deprecs iface)
+       ]
+  where
+    pp_boot | mi_boot iface = ptext SLIT("[boot]")
+           | otherwise     = empty
+
+    exp_vers  = mi_exp_vers iface
+    rule_vers = mi_rule_vers iface
+
+    pp_sub_vers | exp_vers == initialVersion && rule_vers == initialVersion = empty
+               | otherwise = brackets (ppr exp_vers <+> ppr rule_vers)
+\end{code}
+
+When printing export lists, we print like this:
+       Avail   f               f
+       AvailTC C [C, x, y]     C(x,y)
+       AvailTC C [x, y]        C!(x,y)         -- Exporting x, y but not C
+
+\begin{code}
+pprExport :: IfaceExport -> SDoc
+pprExport (mod, items)
+ = hsep [ ptext SLIT("export"), ppr mod, hsep (map pp_avail items) ]
+  where
+    pp_avail :: GenAvailInfo OccName -> SDoc
+    pp_avail (Avail occ)    = ppr occ
+    pp_avail (AvailTC _ []) = empty
+    pp_avail (AvailTC n (n':ns)) 
+       | n==n'     = ppr n <> pp_export ns
+       | otherwise = ppr n <> char '|' <> pp_export (n':ns)
+    
+    pp_export []    = empty
+    pp_export names = braces (hsep (map ppr names))
+
+pprUsage :: Usage -> SDoc
+pprUsage usage
+  = hsep [ptext SLIT("import"), ppr (usg_name usage), 
+         int (usg_mod usage), 
+         pp_export_version (usg_exports usage),
+         int (usg_rules usage),
+         pp_versions (usg_entities usage) ]
+  where
+    pp_versions nvs = hsep [ ppr n <+> int v | (n,v) <- nvs ]
+    pp_export_version Nothing  = empty
+    pp_export_version (Just v) = int v
+
+pprDeps :: Dependencies -> SDoc
+pprDeps (Deps { dep_mods = mods, dep_pkgs = pkgs, dep_orphs = orphs})
+  = vcat [ptext SLIT("module dependencies:") <+> fsep (map ppr_mod mods),
+         ptext SLIT("package dependencies:") <+> fsep (map ppr pkgs), 
+         ptext SLIT("orphans:") <+> fsep (map ppr orphs)
+       ]
+  where
+    ppr_mod (mod_name, boot) = ppr mod_name <+> ppr_boot boot
+    ppr_boot True  = text "[boot]"
+    ppr_boot False = empty
+
+pprIfaceDecl :: (Version, IfaceDecl) -> SDoc
+pprIfaceDecl (ver, decl)
+  = ppr_vers ver <+> ppr decl
+  where
+       -- Print the version for the decl
+    ppr_vers v | v == initialVersion = empty
+              | otherwise           = int v
+
+pprFixities :: [(OccName, Fixity)] -> SDoc
+pprFixities []    = empty
+pprFixities fixes = ptext SLIT("fixities") <+> pprWithCommas pprFix fixes
+                 where
+                   pprFix (occ,fix) = ppr fix <+> ppr occ 
+
+pprDeprecs NoDeprecs       = empty
+pprDeprecs (DeprecAll txt)  = ptext SLIT("Deprecate all") <+> doubleQuotes (ftext txt)
+pprDeprecs (DeprecSome prs) = ptext SLIT("Deprecate") <+> vcat (map pprDeprec prs)
+                           where
+                             pprDeprec (name, txt) = ppr name <+> doubleQuotes (ftext txt)
+\end{code}
+
+
 %*********************************************************
 %*                                                      *
 \subsection{Errors}
@@ -579,3 +663,4 @@ wrongIfaceModErr iface mod_name file_path
        ]
   where iface_file = doubleQuotes (text file_path)
 \end{code}
+