[project @ 2000-11-14 11:25:22 by simonpj]
[ghc-hetmet.git] / ghc / compiler / main / MkIface.lhs
index c911132..9ff18cb 100644 (file)
@@ -5,7 +5,8 @@
 
 \begin{code}
 module MkIface ( 
-       mkModDetails, mkModDetailsFromIface, completeIface, writeIface
+       mkModDetails, mkModDetailsFromIface, completeIface, 
+       writeIface, pprIface
   ) where
 
 #include "HsVersions.h"
@@ -14,17 +15,20 @@ import HsSyn
 import HsCore          ( HsIdInfo(..), UfExpr(..), toUfExpr, toUfBndr )
 import HsTypes         ( toHsTyVars )
 import BasicTypes      ( Fixity(..), NewOrData(..),
-                         Version, bumpVersion, isLoopBreaker
+                         Version, initialVersion, bumpVersion, isLoopBreaker
                        )
 import RnMonad
 import RnHsSyn         ( RenamedInstDecl, RenamedTyClDecl )
 import TcHsSyn         ( TypecheckedRuleDecl )
-import HscTypes                ( VersionInfo(..), IfaceDecls(..), ModIface(..), ModDetails(..),
-                         TyThing(..), DFunId, TypeEnv, isTyClThing
+import HscTypes                ( VersionInfo(..), ModIface(..), ModDetails(..),
+                         IfaceDecls, mkIfaceDecls, dcl_tycl, dcl_rules, dcl_insts,
+                         TyThing(..), DFunId, TypeEnv, isTyClThing, Avails,
+                         WhatsImported(..), GenAvailInfo(..), 
+                         ImportVersion, AvailInfo, Deprecations(..)
                        )
 
 import CmdLineOpts
-import Id              ( Id, idType, idInfo, omitIfaceSigForId, isUserExportedId, hasNoBinding,
+import Id              ( Id, idType, idInfo, omitIfaceSigForId, isExportedId, hasNoBinding,
                          idSpecialisation, idName, setIdInfo
                        )
 import Var             ( isId )
@@ -35,23 +39,23 @@ import CoreSyn              ( CoreExpr, CoreBind, Bind(..), CoreRule(..), IdCoreRule,
                          isBuiltinRule, rulesRules, rulesRhsFreeVars, emptyCoreRules,
                          bindersOfBinds
                        )
-import CoreFVs         ( exprSomeFreeVars, ruleSomeLhsFreeVars, ruleSomeFreeVars )
+import CoreFVs         ( exprSomeFreeVars, ruleSomeLhsFreeVars, ruleSomeFreeVars, mustHaveLocalBinding )
 import CoreUnfold      ( okToUnfoldInHiFile, mkTopUnfolding, neverUnfold, unfoldingTemplate, noUnfolding )
-import Name            ( isLocallyDefined, getName, 
-                         Name, NamedThing(..),
-                         plusNameEnv, lookupNameEnv, emptyNameEnv, mkNameEnv,
-                         extendNameEnv, lookupNameEnv_NF, nameEnvElts
-                       )
+import Name            ( getName, nameModule, Name, NamedThing(..) )
+import Name    -- Env
+import OccName         ( pprOccName )
 import TyCon           ( TyCon, getSynTyConDefn, isSynTyCon, isNewTyCon, isAlgTyCon,
-                         tyConTheta, tyConTyVars, tyConDataCons, tyConFamilySize
+                         tyConTheta, tyConTyVars, tyConDataCons, tyConFamilySize, isClassTyCon
                        )
 import Class           ( classExtraBigSig, DefMeth(..) )
 import FieldLabel      ( fieldLabelType )
 import Type            ( splitSigmaTy, tidyTopType, deNoteType )
 import SrcLoc          ( noSrcLoc )
 import Outputable
+import Module          ( ModuleName )
 
 import List            ( partition )
+import IO              ( IOMode(..), openFile, hClose )
 \end{code}
 
 
@@ -74,8 +78,17 @@ mkModDetails type_env dfun_ids tidy_binds stg_ids orphan_rules
   where
        -- The competed type environment is gotten from
        --      a) keeping the types and classes
-       --      b) removing all Ids, and Ids with correct IdInfo
+       --      b) removing all Ids, 
+       --      c) adding Ids with correct IdInfo, including unfoldings,
        --              gotten from the bindings
+       -- From (c) we keep only those Ids with Global names, plus Ids
+       --          accessible from them (notably via unfoldings)
+       -- This truncates the type environment to include only the 
+       -- exported Ids and things needed from them, which saves space
+       --
+       -- However, we do keep things like constructors, which should not appear 
+       -- in interface files, because they are needed by importing modules when
+       -- using the compilation manager
     new_type_env = mkNameEnv [(getName tycl, tycl) | tycl <- orig_type_env, isTyClThing tycl]
                        `plusNameEnv`
                   mkNameEnv [(idName id, AnId id) | id <- final_ids]
@@ -113,25 +126,19 @@ mkModDetailsFromIface type_env dfun_ids rules
 completeIface :: Maybe ModIface                -- The old interface, if we have it
              -> ModIface               -- The new one, minus the decls and versions
              -> ModDetails             -- The ModDetails for this module
-             -> Maybe (ModIface, SDoc) -- The new one, complete with decls and versions
+             -> (ModIface, Maybe SDoc) -- The new one, complete with decls and versions
                                        -- The SDoc is a debug document giving differences
                                        -- Nothing => no change
 
        -- NB: 'Nothing' means that even the usages havn't changed, so there's no
        --     need to write a new interface file.  But even if the usages have
        --     changed, the module version may not have.
-       --
-       -- The IO in the type is solely for debug output
-       -- In particular, dumping a record of what has changed
 completeIface maybe_old_iface new_iface mod_details 
   = addVersionInfo maybe_old_iface (new_iface { mi_decls = new_decls })
   where
-     new_decls = IfaceDecls { dcl_tycl  = ty_cls_dcls,
-                             dcl_insts = inst_dcls,
-                             dcl_rules = rule_dcls }
-
+     new_decls   = mkIfaceDecls ty_cls_dcls rule_dcls inst_dcls
      inst_dcls   = map ifaceInstance (md_insts mod_details)
-     ty_cls_dcls = map ifaceTyCls (nameEnvElts (md_types mod_details))
+     ty_cls_dcls = foldNameEnv ifaceTyCls [] (md_types mod_details)
      rule_dcls   = map ifaceRule (md_rules mod_details)
 \end{code}
 
@@ -143,19 +150,21 @@ completeIface maybe_old_iface new_iface mod_details
 %************************************************************************
 
 \begin{code}
-ifaceTyCls :: TyThing -> RenamedTyClDecl
-ifaceTyCls (AClass clas)
-  = ClassDecl (toHsContext sc_theta)
-             (getName clas)
-             (toHsTyVars clas_tyvars)
-             (toHsFDs clas_fds)
-             (map toClassOpSig op_stuff)
-             EmptyMonoBinds
-             [] noSrcLoc
+ifaceTyCls :: TyThing -> [RenamedTyClDecl] -> [RenamedTyClDecl]
+ifaceTyCls (AClass clas) so_far
+  = cls_decl : so_far
   where
-     (clas_tyvars, clas_fds, sc_theta, _, op_stuff) = classExtraBigSig clas
+    cls_decl = ClassDecl (toHsContext sc_theta)
+                        (getName clas)          
+                        (toHsTyVars clas_tyvars)
+                        (toHsFDs clas_fds)
+                        (map toClassOpSig op_stuff)
+                        EmptyMonoBinds
+                        [] noSrcLoc
 
-     toClassOpSig (sel_id, def_meth)
+    (clas_tyvars, clas_fds, sc_theta, _, op_stuff) = classExtraBigSig clas
+
+    toClassOpSig (sel_id, def_meth)
        = ASSERT(sel_tyvars == clas_tyvars)
          ClassOpSig (getName sel_id) (Just def_meth') (toHsType op_ty) noSrcLoc
        where
@@ -165,22 +174,26 @@ ifaceTyCls (AClass clas)
                         GenDefMeth -> GenDefMeth
                         DefMeth id -> DefMeth (getName id)
 
-ifaceTyCls (ATyCon tycon)
-  | isSynTyCon tycon
-  = TySynonym (getName tycon)(toHsTyVars tyvars) (toHsType ty) noSrcLoc
-  where
-    (tyvars, ty) = getSynTyConDefn tycon
-
-ifaceTyCls (ATyCon tycon)
-  | isAlgTyCon tycon
-  = TyData new_or_data (toHsContext (tyConTheta tycon))
-          (getName tycon)
-          (toHsTyVars tyvars)
-          (map ifaceConDecl (tyConDataCons tycon))
-          (tyConFamilySize tycon)
-          Nothing noSrcLoc (panic "gen1") (panic "gen2")
+ifaceTyCls (ATyCon tycon) so_far
+  | isClassTyCon tycon = so_far
+  | otherwise         = ty_decl : so_far
   where
-    tyvars = tyConTyVars tycon
+    ty_decl | isSynTyCon tycon
+           = TySynonym (getName tycon)(toHsTyVars tyvars) 
+                       (toHsType syn_ty) noSrcLoc
+
+           | isAlgTyCon tycon
+           = TyData new_or_data (toHsContext (tyConTheta tycon))
+                    (getName tycon)      
+                    (toHsTyVars tyvars)
+                    (map ifaceConDecl (tyConDataCons tycon))
+                    (tyConFamilySize tycon)
+                    Nothing noSrcLoc (panic "gen1") (panic "gen2")
+
+           | otherwise = pprPanic "ifaceTyCls" (ppr tycon)
+
+    tyvars      = tyConTyVars tycon
+    (_, syn_ty) = getSynTyConDefn tycon
     new_or_data | isNewTyCon tycon = NewType
                | otherwise        = DataType
 
@@ -207,11 +220,12 @@ ifaceTyCls (ATyCon tycon)
     mk_field strict_mark field_label
        = ([getName field_label], mk_bang_ty strict_mark (fieldLabelType field_label))
 
-ifaceTyCls (ATyCon tycon) = pprPanic "ifaceTyCls" (ppr tycon)
-
-ifaceTyCls (AnId id) 
-  = IfaceSig (getName id) (toHsType id_type) hs_idinfo noSrcLoc
+ifaceTyCls (AnId id) so_far
+  | omitIfaceSigForId id = so_far
+  | otherwise           = iface_sig : so_far
   where
+    iface_sig = IfaceSig (getName id) (toHsType id_type) hs_idinfo noSrcLoc
+
     id_type = idType id
     id_info = idInfo id
 
@@ -260,7 +274,7 @@ ifaceTyCls (AnId id)
 %*                                                                     *
 %************************************************************************
 
-\begin{code}                    
+\begin{code}
 ifaceInstance :: DFunId -> RenamedInstDecl
 ifaceInstance dfun_id
   = InstDecl (toHsType tidy_ty) EmptyMonoBinds [] (Just (getName dfun_id)) noSrcLoc                     
@@ -312,7 +326,7 @@ bindsToIds needed_ids codegen_ids binds
        -- The 'needed' set contains the Ids that are needed by earlier
        -- interface file emissions.  If the Id isn't in this set, and isn't
        -- exported, there's no need to emit anything
-    need_id needed_set id = id `elemVarSet` needed_set || isUserExportedId id 
+    need_id needed_set id = id `elemVarSet` needed_set || isExportedId id 
 
     go needed [] emitted
        | not (isEmptyVarSet needed) = pprTrace "ifaceBinds: free vars:" 
@@ -321,17 +335,11 @@ bindsToIds needed_ids codegen_ids binds
        | otherwise                  = emitted
 
     go needed (NonRec id rhs : binds) emitted
-       | need_id needed id
-       = if omitIfaceSigForId id then
-           go (needed `delVarSet` id) binds (id:emitted)
-         else
-           go ((needed `unionVarSet` extras) `delVarSet` id)
-              binds
-              (new_id:emitted)
-       | otherwise
-       = go needed binds emitted
+       | need_id needed id = go new_needed binds (new_id:emitted)
+       | otherwise         = go needed     binds emitted
        where
          (new_id, extras) = mkFinalId codegen_ids False id rhs
+         new_needed       = (needed `unionVarSet` extras) `delVarSet` id
 
        -- Recursive groups are a bit more of a pain.  We may only need one to
        -- start with, but it may call out the next one, and so on.  So we
@@ -364,12 +372,15 @@ bindsToIds needed_ids codegen_ids binds
 
 \begin{code}
 mkFinalId :: IdSet             -- The Ids with arity info from the code generator
-         -> Bool                       -- True <=> recursive, so don't include unfolding
+         -> Bool               -- True <=> recursive, so don't include unfolding
          -> Id
          -> CoreExpr           -- The Id's right hand side
-         -> (Id, IdSet)                -- The emitted id, plus any *extra* needed Ids
+         -> (Id, IdSet)        -- The emitted id, plus any *extra* needed Ids
 
 mkFinalId codegen_ids is_rec id rhs
+  | omitIfaceSigForId id 
+  = (id, emptyVarSet)          -- An optimisation for top-level constructors and suchlike
+  | otherwise
   = (id `setIdInfo` new_idinfo, new_needed_ids)
   where
     core_idinfo = idInfo id
@@ -379,7 +390,7 @@ mkFinalId codegen_ids is_rec id rhs
                                    idInfo id
 
     new_idinfo | opt_OmitInterfacePragmas
-              = vanillaIdInfo
+              = constantIdInfo
               | otherwise                
               = core_idinfo `setArityInfo`      arity_info
                             `setCafInfo`        cafInfo stg_idinfo
@@ -435,7 +446,7 @@ mkFinalId codegen_ids is_rec id rhs
     bottoming_fn   = isBottomingStrictness (strictnessInfo core_idinfo)
 
     unfolding    = mkTopUnfolding rhs
-    rhs_is_small = neverUnfold unfolding
+    rhs_is_small = not (neverUnfold unfolding)
 
     unfold_info | show_unfold = unfolding
                | otherwise   = noUnfolding
@@ -466,7 +477,7 @@ mkFinalId codegen_ids is_rec id rhs
 
     find_fvs expr = exprSomeFreeVars interestingId expr
 
-interestingId id = isId id && isLocallyDefined id && not (hasNoBinding id)
+interestingId id = isId id && mustHaveLocalBinding id
 \end{code}
 
 
@@ -506,7 +517,7 @@ getRules orphan_rules binds emitted
 \begin{code}
 addVersionInfo :: Maybe ModIface               -- The old interface, read from M.hi
               -> ModIface                      -- The new interface decls
-              -> Maybe (ModIface, SDoc)        -- Nothing => no change; no need to write new Iface
+              -> (ModIface, Maybe SDoc)        -- Nothing => no change; no need to write new Iface
                                                -- Just mi => Here is the new interface to write
                                                --            with correct version numbers
 
@@ -516,7 +527,7 @@ addVersionInfo :: Maybe ModIface            -- The old interface, read from M.hi
 
 addVersionInfo Nothing new_iface
 -- No old interface, so definitely write a new one!
-  = Just (new_iface, text "No old interface available")
+  = (new_iface, Just (text "No old interface available"))
 
 addVersionInfo (Just old_iface@(ModIface { mi_version = old_version, 
                                           mi_decls   = old_decls,
@@ -525,10 +536,10 @@ addVersionInfo (Just old_iface@(ModIface { mi_version = old_version,
                                     mi_fixities = new_fixities })
 
   | no_output_change && no_usage_change
-  = Nothing
+  = (old_iface, Nothing)
 
   | otherwise          -- Add updated version numbers
-  = Just (final_iface, pp_tc_diffs)
+  = (final_iface, Just pp_tc_diffs)
        
   where
     final_iface = new_iface { mi_version = new_version }
@@ -571,7 +582,7 @@ diffDecls old_vers old_fixities new_fixities old new
     diff ok_so_far pp new_vers old []      = (False,     pp, new_vers)
     diff ok_so_far pp new_vers [] (nd:nds) = diff False (pp $$ only_new nd) new_vers [] nds
     diff ok_so_far pp new_vers (od:ods) (nd:nds)
-       = case od_name `compare` nd_name of
+       = case nameOccName od_name `compare` nameOccName nd_name of
                LT -> diff False (pp $$ only_old od) new_vers ods      (nd:nds)
                GT -> diff False (pp $$ only_new nd) new_vers (od:ods) nds
                EQ | od `eq_tc` nd -> diff ok_so_far pp                    new_vers  ods nds
@@ -597,14 +608,18 @@ diffDecls old_vers old_fixities new_fixities old new
 %************************************************************************
 
 \begin{code}
-writeIface :: Finder -> ModIface -> IO ()
-writeIface finder mod_iface
-  = do { let filename = error "... find the right file..."
-       ; if_hdl <- openFile filename WriteMode
-       ; printForIface if_hdl (pprIface mod_iface)
+writeIface :: FilePath -> ModIface -> IO ()
+writeIface hi_path mod_iface
+  = do { if_hdl <- openFile hi_path WriteMode
+       ; printForIface if_hdl from_this_mod (pprIface mod_iface)
        ; hClose if_hdl
        }
-
+  where
+       -- Print names unqualified if they are from this module
+    from_this_mod n = nameModule n == this_mod
+    this_mod = mi_module mod_iface
+        
+pprIface :: ModIface -> SDoc
 pprIface iface
  = vcat [ ptext SLIT("__interface")
                <+> doubleQuotes (ptext opt_InPackage)
@@ -614,17 +629,16 @@ pprIface iface
                <+> int opt_HiVersion
                <+> ptext SLIT("where")
 
-       , pprExports (mi_exports iface)
+       , vcat (map pprExport (mi_exports iface))
        , vcat (map pprUsage (mi_usages iface))
 
-       , pprIfaceDecls (vers_decls version_info) 
-                       (mi_fixities iface)
-                       (mi_decls iface)
-
+       , pprFixities (mi_fixities iface) (dcl_tycl decls)
+       , pprIfaceDecls (vers_decls version_info) decls
        , pprDeprecs (mi_deprecs iface)
        ]
   where
-    version_info = mi_version mod_iface
+    version_info = mi_version iface
+    decls       = mi_decls iface
     exp_vers     = vers_exports version_info
     rule_vers   = vers_rules version_info
 
@@ -640,26 +654,26 @@ When printing export lists, we print like this:
 \begin{code}
 pprExport :: (ModuleName, Avails) -> SDoc
 pprExport (mod, items)
- = hsep [ ptext SLIT("__export "), ppr mod, hsep (map upp_avail items) ] <> semi
+ = hsep [ ptext SLIT("__export "), ppr mod, hsep (map pp_avail items) ] <> semi
   where
-    pp_avail :: RdrAvailInfo -> SDoc
-    pp_avail (Avail name)      = pprOccName name
-    pp_avail (AvailTC name []) = empty
-    pp_avail (AvailTC name ns) = hcat [pprOccName name, bang, upp_export ns']
-                               where
-                                 bang | name `elem` ns = empty
-                                      | otherwise      = char '|'
-                                 ns' = filter (/= name) ns
+    pp_avail :: AvailInfo -> SDoc
+    pp_avail (Avail name)                   = pprOcc name
+    pp_avail (AvailTC n [])                 = empty
+    pp_avail (AvailTC n (n':ns)) | n==n'     = pprOcc n                    <> pp_export ns
+                                | otherwise = pprOcc n <> char '|' <> pp_export (n':ns)
     
     pp_export []    = empty
-    pp_export names = braces (hsep (map pprOccName names))
+    pp_export names = braces (hsep (map pprOcc names))
+
+pprOcc :: Name -> SDoc -- Print the occurrence name only
+pprOcc n = pprOccName (nameOccName n)
 \end{code}
 
 
 \begin{code}
 pprUsage :: ImportVersion Name -> SDoc
 pprUsage (m, has_orphans, is_boot, whats_imported)
-  = hsep [ptext SLIT("import"), pprModuleName m, 
+  = hsep [ptext SLIT("import"), ppr m, 
          pp_orphan, pp_boot,
          pp_versions whats_imported
     ] <> semi
@@ -673,7 +687,7 @@ pprUsage (m, has_orphans, is_boot, whats_imported)
     pp_versions NothingAtAll                       = empty
     pp_versions (Everything v)                     = dcolon <+> int v
     pp_versions (Specifically vm ve nvs vr) = dcolon <+> int vm <+> pp_export_version ve <+> int vr 
-                                             <+> hsep [ ppr n <+> int v | (n,v) <- nvs ]
+                                             <+> hsep [ pprOcc n <+> int v | (n,v) <- nvs ]
 
        -- HACK for the moment: print the export-list version even if
        -- we don't use it, so that syntax of interface files doesn't change
@@ -682,34 +696,38 @@ pprUsage (m, has_orphans, is_boot, whats_imported)
 \end{code}
 
 \begin{code}
-pprIfaceDecls version_map fixity_map decls
+pprIfaceDecls version_map decls
   = vcat [ vcat [ppr i <+> semi | i <- dcl_insts decls]
         , vcat (map ppr_decl (dcl_tycl decls))
         , pprRules (dcl_rules decls)
         ]
   where
-    ppr_decl d  = (ppr_vers d <+> ppr d <> semi) $$ ppr_fixes d
+    ppr_decl d  = ppr_vers d <+> ppr d <> semi
 
        -- Print the version for the decl
     ppr_vers d = case lookupNameEnv version_map (tyClDeclName d) of
                   Nothing -> empty
                   Just v  -> int v
-
-       -- Print fixities relevant to the decl
-    ppr_fixes d = vcat (map ppr_fix (fixities d))
-    fixities d  = [ ppr fix <+> ppr n <> semi
-                 | n <- tyClDeclNames d, 
-                   [Just fix] <- lookupNameEnv fixity_map n
-                 ]
 \end{code}
 
 \begin{code}
+pprFixities fixity_map decls
+  = hsep [ ppr fix <+> ppr n 
+        | d <- decls, 
+          (n,_) <- tyClDeclNames d, 
+          Just fix <- [lookupNameEnv fixity_map n]] <> semi
+
 pprRules []    = empty
 pprRules rules = hsep [ptext SLIT("{-## __R"), vcat (map ppr rules), ptext SLIT("##-}")]
 
-pprDeprecs []   = empty
-pprDeprecs deps = hsep [ ptext SLIT("{-## __D"), guts, ptext SLIT("##-}")]
-               where
-                 guts = hsep [ ppr ie <+> doubleQuotes (ppr txt) <> semi 
-                             | Deprecation ie txt _ <- deps ]
+pprDeprecs NoDeprecs = empty
+pprDeprecs deprecs   = ptext SLIT("{-## __D") <+> guts <+> ptext SLIT("##-}")
+                    where
+                      guts = case deprecs of
+                               DeprecAll txt  -> doubleQuotes (ptext txt)
+                               DeprecSome env -> pp_deprecs env
+
+pp_deprecs env = vcat (punctuate semi (map pp_deprec (nameEnvElts env)))
+              where
+                pp_deprec (name, txt) = pprOcc name <+> doubleQuotes (ptext txt)
 \end{code}