[project @ 2003-10-02 19:20:59 by sof]
[ghc-hetmet.git] / ghc / compiler / main / MkIface.lhs
index 9388e34..9f31e70 100644 (file)
@@ -24,22 +24,22 @@ import NewDemand    ( isTopSig )
 import TcRnMonad
 import TcRnTypes       ( ImportAvails(..) )
 import RnHsSyn         ( RenamedInstDecl, RenamedTyClDecl )
-import HscTypes                ( VersionInfo(..), ModIface(..), HomeModInfo(..),
+import HscTypes                ( VersionInfo(..), ModIface(..), 
                          ModGuts(..), ModGuts, 
-                         GhciMode(..), HscEnv(..),
+                         GhciMode(..), HscEnv(..), Dependencies(..),
                          FixityEnv, lookupFixity, collectFixities,
                          IfaceDecls, mkIfaceDecls, dcl_tycl, dcl_rules, dcl_insts,
-                         TyThing(..), DFunId, Dependencies,
+                         TyThing(..), DFunId, 
                          Avails, AvailInfo, GenAvailInfo(..), availName, 
                          ExternalPackageState(..),
                          ParsedIface(..), Usage(..),
                          Deprecations(..), initialVersionInfo,
-                         lookupVersion
+                         lookupVersion, lookupIfaceByModName
                        )
 
 import CmdLineOpts
-import Id              ( idType, idInfo, isImplicitId, idCgInfo )
-import DataCon         ( dataConSig, dataConFieldLabels, dataConStrictMarks )
+import Id              ( idType, idInfo, isImplicitId, idCafInfo )
+import DataCon         ( dataConName, dataConSig, dataConFieldLabels, dataConStrictMarks )
 import IdInfo          -- Lots
 import CoreSyn         ( CoreRule(..), IdCoreRule )
 import CoreFVs         ( ruleLhsFreeNames )
@@ -53,23 +53,26 @@ import TyCon                ( DataConDetails(..), tyConTyVars, tyConDataCons, tyConTheta,
                          isFunTyCon, isPrimTyCon, isNewTyCon, isClassTyCon, 
                          isSynTyCon, isAlgTyCon, isForeignTyCon,
                          getSynTyConDefn, tyConGenInfo, tyConDataConDetails, tyConArity )
-import Class           ( classExtraBigSig, classTyCon, DefMeth(..) )
+import Class           ( classExtraBigSig, classTyCon )
 import FieldLabel      ( fieldLabelType )
-import TcType          ( tcSplitSigmaTy, tidyTopType, deNoteType, tyClsNamesOfDFunHead )
+import TcType          ( tcSplitForAllTys, tcFunResultTy, tidyTopType, deNoteType, tyClsNamesOfDFunHead,
+                         mkSigmaTy, mkFunTys, mkTyConApp, mkTyVarTys )
 import SrcLoc          ( noSrcLoc )
 import Module          ( Module, ModuleName, moduleNameFS, moduleName, isHomeModule,
-                         ModLocation(..), mkSysModuleNameFS,
-                         ModuleEnv, emptyModuleEnv, foldModuleEnv, lookupModuleEnv,
-                         extendModuleEnv_C, elemModuleSet, moduleEnvElts, elemModuleEnv
+                         ModLocation(..), mkSysModuleNameFS, 
+                         ModuleEnv, emptyModuleEnv, lookupModuleEnv,
+                         extendModuleEnv_C, moduleEnvElts 
                        )
 import Outputable
+import DriverUtil      ( createDirectoryHierarchy, directoryOf )
 import Util            ( sortLt, dropList, seqList )
 import Binary          ( getBinFileWithDict )
-import BinIface                ( writeBinIface )
+import BinIface                ( writeBinIface, v_IgnoreHiVersion )
 import ErrUtils                ( dumpIfSet_dyn )
 import FiniteMap
 import FastString
 
+import DATA_IOREF      ( writeIORef )
 import Monad           ( when )
 import Maybe           ( catMaybes, isJust, isNothing )
 import Maybes          ( orElse )
@@ -86,6 +89,9 @@ import IO             ( putStrLn )
 \begin{code}
 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
    parsed_iface <- Binary.getBinFileWithDict filename
    let ParsedIface{
       pi_mod=pi_mod, pi_pkg=pi_pkg, pi_vers=pi_vers,
@@ -163,9 +169,9 @@ mkIface hsc_env location maybe_old_iface
        ; let (final_iface, maybe_diffs) = _scc_ "versioninfo" addVersionInfo maybe_old_iface iface_w_decls
 
                -- Write the interface file, if necessary
-       ; when (must_write_hi_file maybe_diffs)
-               (writeBinIface hi_file_path final_iface)
---             (writeIface hi_file_path final_iface)
+       ; when (must_write_hi_file maybe_diffs) $ do
+               createDirectoryHierarchy (directoryOf hi_file_path)
+               writeBinIface hi_file_path final_iface
 
                -- Debug printing
        ; write_diffs dflags final_iface maybe_diffs
@@ -176,6 +182,7 @@ mkIface hsc_env location maybe_old_iface
   where
      dflags    = hsc_dflags hsc_env
      ghci_mode = hsc_mode hsc_env
+     omit_pragmas = dopt Opt_OmitInterfacePragmas dflags
 
      must_write_hi_file Nothing       = False
      must_write_hi_file (Just _diffs) = ghci_mode /= Interactive
@@ -188,7 +195,7 @@ mkIface hsc_env location maybe_old_iface
      hi_file_path = ml_hi_file location
      new_decls    = mkIfaceDecls ty_cls_dcls rule_dcls inst_dcls
      inst_dcls    = map ifaceInstance insts
-     ty_cls_dcls  = foldNameEnv ifaceTyThing_acc [] types
+     ty_cls_dcls  = foldNameEnv (ifaceTyThing_acc omit_pragmas) [] types
      rule_dcls    = map ifaceRule rules
      orphan_mod   = isOrphanModule impl
 
@@ -219,18 +226,21 @@ Implicit Ids and class tycons aren't included in interface files, so
 we miss them out of the accumulating parameter here.
 
 \begin{code}
-ifaceTyThing_acc :: TyThing -> [RenamedTyClDecl] -> [RenamedTyClDecl]
-ifaceTyThing_acc (AnId   id) so_far | isImplicitId id = so_far
-ifaceTyThing_acc (ATyCon id) so_far | isClassTyCon id = so_far
-ifaceTyThing_acc other so_far = ifaceTyThing other : so_far
+ifaceTyThing_acc :: Bool -> TyThing -> [RenamedTyClDecl] -> [RenamedTyClDecl]
+-- Don't put implicit things into the result
+ifaceTyThing_acc omit_pragmas (ADataCon dc) so_far                  = so_far
+ifaceTyThing_acc omit_pragmas (AnId   id)   so_far | isImplicitId id = so_far
+ifaceTyThing_acc omit_pragmas (ATyCon id)   so_far | isClassTyCon id = so_far
+ifaceTyThing_acc omit_pragmas other so_far  
+ = ifaceTyThing omit_pragmas other : so_far
 \end{code}
 
 Convert *any* TyThing into a RenamedTyClDecl.  Used both for
 generating interface files and for the ':info' command in GHCi.
 
 \begin{code}
-ifaceTyThing :: TyThing -> RenamedTyClDecl
-ifaceTyThing (AClass clas) = cls_decl
+ifaceTyThing :: Bool -> TyThing -> RenamedTyClDecl
+ifaceTyThing omit_pragmas (AClass clas) = cls_decl
   where
     cls_decl = ClassDecl { tcdCtxt     = toHsContext sc_theta,
                           tcdName      = getName clas,
@@ -246,15 +256,17 @@ ifaceTyThing (AClass clas) = cls_decl
 
     toClassOpSig (sel_id, def_meth)
        = ASSERT(sel_tyvars == clas_tyvars)
-         ClassOpSig (getName sel_id) def_meth' (toHsType op_ty) noSrcLoc
+         ClassOpSig (getName sel_id) def_meth (toHsType op_ty) noSrcLoc
        where
-         (sel_tyvars, _, op_ty) = tcSplitSigmaTy (idType sel_id)
-         def_meth' = case def_meth of
-                        NoDefMeth  -> NoDefMeth
-                        GenDefMeth -> GenDefMeth
-                        DefMeth id -> DefMeth (getName id)
-
-ifaceTyThing (ATyCon tycon) = ty_decl
+               -- Be careful when splitting the type, because of things
+               -- like         class Foo a where
+               --                op :: (?x :: String) => a -> a
+               -- and          class Baz a where
+               --                op :: (Ord a) => a -> a
+         (sel_tyvars, rho_ty) = tcSplitForAllTys (idType sel_id)
+         op_ty                = tcFunResultTy rho_ty
+
+ifaceTyThing omit_pragmas (ATyCon tycon) = ty_decl
   where
     ty_decl | isSynTyCon tycon
            = TySynonym { tcdName   = getName tycon,
@@ -302,7 +314,7 @@ ifaceTyThing (ATyCon tycon) = ty_decl
     ifaceConDecls (DataCons cs) = DataCons (map ifaceConDecl cs)
 
     ifaceConDecl data_con 
-       = ConDecl (getName data_con)
+       = ConDecl (dataConName data_con)
                  (toHsTyVars ex_tyvars)
                  (toHsContext ex_theta)
                  details noSrcLoc
@@ -322,20 +334,19 @@ ifaceTyThing (ATyCon tycon) = ty_decl
     mk_field strict_mark field_label
        = (getName field_label, BangType strict_mark (toHsType (fieldLabelType field_label)))
 
-ifaceTyThing (AnId id) = iface_sig
+ifaceTyThing omit_pragmas (AnId id) = iface_sig
   where
     iface_sig = IfaceSig { tcdName   = getName id, 
                           tcdType   = toHsType id_type,
                           tcdIdInfo = hs_idinfo,
-                          tcdLoc    =  noSrcLoc }
+                          tcdLoc    = noSrcLoc }
 
     id_type = idType id
     id_info = idInfo id
-    cg_info = idCgInfo id
     arity_info = arityInfo id_info
-    caf_info   = cgCafInfo cg_info
+    caf_info   = idCafInfo id
 
-    hs_idinfo | opt_OmitInterfacePragmas
+    hs_idinfo | omit_pragmas
              = []
              | otherwise
              = catMaybes [arity_hsinfo,  caf_hsinfo,
@@ -373,6 +384,23 @@ ifaceTyThing (AnId id) = iface_sig
     unfold_hsinfo |  neverUnfold unfold_info 
                  || has_worker = Nothing
                  | otherwise   = Just (HsUnfold inline_prag (toUfExpr rhs))
+
+
+ifaceTyThing omit_pragmas (ADataCon dc)
+       -- This case only happens in the call to ifaceThing in InteractiveUI
+       -- Otherwise DataCons are filtered out in ifaceThing_acc
+ = IfaceSig { tcdName   = getName dc, 
+             tcdType   = toHsType full_ty,
+             tcdIdInfo = [],
+             tcdLoc    = noSrcLoc }
+ where
+    (tvs, stupid_theta, ex_tvs, ex_theta, arg_tys, tycon) = dataConSig dc
+
+       -- The "stupid context" isn't part of the wrapper-Id type
+       -- (for better or worse -- see note in DataCon.lhs), so we
+       -- have to make it up here
+    full_ty = mkSigmaTy (tvs ++ ex_tvs) (stupid_theta ++ ex_theta) 
+                       (mkFunTys arg_tys (mkTyConApp tycon (mkTyVarTys tvs)))
 \end{code}
 
 \begin{code}
@@ -476,24 +504,23 @@ mkUsageInfo :: HscEnv -> ExternalPackageState
 
 mkUsageInfo hsc_env eps
            (ImportAvails { imp_mods = dir_imp_mods,
-                           dep_mods = dep_mods })
+                           imp_dep_mods = dep_mods })
            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
   where
-    usages = catMaybes (map mkUsage (moduleEnvElts hpt))
-    hpt    = hsc_HPT hsc_env
+    usages = catMaybes [ mkUsage mod_name 
+                      | (mod_name,_) <- moduleEnvElts dep_mods]
+       -- ToDo: do we need to sort into canonical order?
+
+    hpt = hsc_HPT hsc_env
+    pit = eps_PIT eps
     
     import_all mod = case lookupModuleEnv dir_imp_mods mod of
-                       Just (_,imp_all) -> imp_all
-                       Nothing          -> False
-    
-       -- Find out whether this module is an
-    is_orphan_mod mod = case lookupModuleEnv dep_mods mod of
-                            Just (_, orph, _) -> orph
-                            Nothing           -> False
+                       Just (_, Nothing) -> True
+                       _                 -> False
     
     -- ent_map groups together all the things imported and used
     -- from a particular module in this package
@@ -510,12 +537,14 @@ mkUsageInfo hsc_env eps
     --         (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 :: HomeModInfo -> Maybe (Usage Name)
-    mkUsage mod_info
-      |  null used_names
-      && not all_imported
-      && not orphan_mod
-      = Nothing
+    mkUsage :: ModuleName -> Maybe (Usage Name)
+    mkUsage mod_name
+      |  isNothing maybe_iface -- We can't depend on it if we didn't
+      || not (isHomeModule mod)        -- even open the interface!
+      || (null used_names
+         && not all_imported
+         && not orphan_mod)
+      = Nothing                        -- Record no usage info
     
       | otherwise      
       = Just (Usage { usg_name     = moduleName mod,
@@ -524,12 +553,14 @@ mkUsageInfo hsc_env eps
                      usg_entities = ent_vers,
                      usg_rules    = rules_vers })
       where
-        iface       = hm_iface mod_info
+       maybe_iface  = lookupIfaceByModName hpt pit mod_name
+               -- In one-shot mode, the interfaces for home-package 
+               -- modules accumulate in the PIT not HPT.  Sigh.
+
+        Just iface   = maybe_iface
         mod         = mi_module iface
         version_info = mi_version iface
-       orphan_mod   = mod `elemModuleEnv` dep_mods && mi_orphan iface
-                       -- Only bother if the module is below 
-                       -- us in the import graph
+       orphan_mod   = mi_orphan iface
         version_env  = vers_decls   version_info
         mod_vers     = vers_module  version_info
         rules_vers   = vers_rules   version_info
@@ -542,6 +573,7 @@ mkUsageInfo hsc_env eps
         ent_vers = [(n, lookupVersion version_env n) 
                   | n <- sortLt lt_occ used_names ]
         lt_occ n1 n2 = nameOccName n1 < nameOccName n2
+       -- ToDo: is '<' on OccNames the right thing; may differ between runs?
 \end{code}
 
 \begin{code}
@@ -779,16 +811,15 @@ pprUsage getOcc usage
 
 
 pprDeps :: Dependencies -> SDoc
-pprDeps (mods, pkgs)
+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("package dependencies:") <+> fsep (map ppr pkgs), 
+         ptext SLIT("orphans:") <+> fsep (map ppr orphs)
+       ]
   where
-    ppr_mod (mod_name, orph, boot)
-      = ppr mod_name <+> ppr_orphan orph <+> ppr_boot boot
+    ppr_mod (mod_name, boot) = ppr mod_name <+> ppr_boot boot
    
-    ppr_orphan True  = char '!'
-    ppr_orphan False = empty
-    ppr_boot   True  = char '@'
+    ppr_boot   True  = text "[boot]"
     ppr_boot   False = empty
 \end{code}