[project @ 2000-04-07 15:24:15 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / Rename.lhs
index f95b222..5a563a0 100644 (file)
@@ -14,46 +14,44 @@ import RnHsSyn              ( RenamedHsModule, RenamedHsDecl,
                          extractHsTyNames, extractHsCtxtTyNames
                        )
 
-import CmdLineOpts     ( opt_HiMap, opt_D_dump_rn_trace,
-                         opt_D_dump_rn, opt_D_dump_rn_stats,
-                         opt_WarnUnusedBinds, opt_WarnUnusedImports
+import CmdLineOpts     ( opt_HiMap, opt_D_dump_rn_trace, opt_D_dump_minimal_imports,
+                         opt_D_dump_rn, opt_D_dump_rn_stats, opt_WarnDeprecations
                        )
 import RnMonad
 import RnNames         ( getGlobalNames )
 import RnSource                ( rnSourceDecls, rnDecl )
-import RnIfaces                ( getImportedInstDecls, importDecl, getImportVersions,
+import RnIfaces                ( getImportedInstDecls, importDecl, getImportVersions, getInterfaceExports,
                          getImportedRules, loadHomeInterface, getSlurped, removeContext
                        )
-import RnEnv           ( availName, availNames, availsToNameSet, 
-                         warnUnusedImports, warnUnusedLocalBinds, mapFvRn, lookupImplicitOccRn,
+import RnEnv           ( availName, availsToNameSet, unitAvailEnv, availEnvElts, plusAvailEnv, 
+                         warnUnusedImports, warnUnusedLocalBinds, lookupImplicitOccRn, pprAvail,
                          FreeVars, plusFVs, plusFV, unitFV, emptyFVs, isEmptyFVs
                        )
-import Module           ( Module, ModuleName, pprModule, mkSearchPath, mkThisModule )
-import Name            ( Name, isLocallyDefined,
-                         NamedThing(..), ImportReason(..), Provenance(..),
-                         pprOccName, nameOccName, nameUnique,
-                         getNameProvenance, isUserImportedExplicitlyName,
+import Module           ( Module, ModuleName, WhereFrom(..),
+                         moduleNameUserString, mkSearchPath, moduleName, mkThisModule
+                       )
+import Name            ( Name, isLocallyDefined, NamedThing(..), getSrcLoc,
+                         nameOccName, nameUnique, nameModule, maybeUserImportedFrom,
+                         isUserImportedExplicitlyName, isUserImportedName,
                          maybeWiredInTyConName, maybeWiredInIdName, isWiredInName
                        )
+import OccName         ( occNameFlavour, isValOcc )
 import Id              ( idType )
-import DataCon         ( dataConTyCon, dataConType )
-import TyCon           ( TyCon, tyConDataCons, isSynTyCon, getSynTyConDefn )
-import RdrName         ( RdrName )
+import TyCon           ( isSynTyCon, getSynTyConDefn )
 import NameSet
-import PrelMods                ( mAIN_Name, pREL_MAIN_Name )
+import PrelMods                ( mAIN_Name, pREL_MAIN_Name, pRELUDE_Name )
 import TysWiredIn      ( unitTyCon, intTyCon, doubleTyCon, boolTyCon )
 import PrelInfo                ( ioTyCon_NAME, thinAirIdNames, fractionalClassKeys, derivingOccurrences )
 import Type            ( namesOfType, funTyCon )
 import ErrUtils                ( printErrorsAndWarnings, dumpIfSet, ghcExit )
 import BasicTypes      ( NewOrData(..) )
 import Bag             ( isEmptyBag, bagToList )
-import FiniteMap       ( fmToList, delListFromFM, addToFM, sizeFM, eltsFM )
+import FiniteMap       ( FiniteMap, eltsFM, fmToList, emptyFM, addToFM_C )
 import UniqSupply      ( UniqSupply )
 import UniqFM          ( lookupUFM )
-import Util            ( equivClasses )
 import Maybes          ( maybeToBool )
-import SrcLoc          ( mkBuiltinSrcLoc )
 import Outputable
+import IO              ( openFile, IOMode(..) )
 \end{code}
 
 
@@ -69,7 +67,7 @@ renameModule :: UniqSupply
                      , [ModuleName]      -- Imported modules; for profiling
                      ))
 
-renameModule us this_mod@(HsModule mod_name vers exports imports local_decls loc)
+renameModule us this_mod@(HsModule mod_name vers exports imports local_decls _ loc)
   =    -- Initialise the renamer monad
     initRn mod_name us (mkSearchPath opt_HiMap) loc
           (rename this_mod)                            >>=
@@ -90,7 +88,9 @@ renameModule us this_mod@(HsModule mod_name vers exports imports local_decls loc
 
 
 \begin{code}
-rename this_mod@(HsModule mod_name vers _ imports local_decls loc)
+rename :: RdrNameHsModule
+       -> RnMG (Maybe (Module, RenamedHsModule, InterfaceDetails, RnNameSupply, [ModuleName]), IO ())
+rename this_mod@(HsModule mod_name vers _ imports local_decls mod_deprec loc)
   =    -- FIND THE GLOBAL NAME ENVIRONMENT
     getGlobalNames this_mod                    `thenRn` \ maybe_stuff ->
 
@@ -102,6 +102,7 @@ rename this_mod@(HsModule mod_name vers _ imports local_decls loc)
     else
     let
        Just (export_env, gbl_env, fixity_env, global_avail_env) = maybe_stuff
+        ExportEnv export_avails _ _ = export_env
     in
 
        -- RENAME THE SOURCE
@@ -112,14 +113,25 @@ rename this_mod@(HsModule mod_name vers _ imports local_decls loc)
        -- SLURP IN ALL THE NEEDED DECLARATIONS
     implicitFVs mod_name rn_local_decls        `thenRn` \ implicit_fvs -> 
     let
-       real_source_fvs = implicit_fvs `plusFV` source_fvs
+       real_source_fvs = implicit_fvs `plusFV` source_fvs `plusFV` export_fvs
                -- It's important to do the "plus" this way round, so that
                -- when compiling the prelude, locally-defined (), Bool, etc
                -- override the implicit ones. 
+
+               -- The export_fvs make the exported names look just as if they
+               -- occurred in the source program.  For the reasoning, see the
+               -- comments with RnIfaces.getImportVersions
+       export_fvs = mkNameSet (map availName export_avails)
     in
     slurpImpDecls real_source_fvs      `thenRn` \ rn_imp_decls ->
     let
        rn_all_decls       = rn_local_decls ++ rn_imp_decls
+
+       -- COLLECT ALL DEPRECATIONS
+       deprec_sigs = [ ds | ValD bnds <- rn_local_decls, ds <- collectDeprecs bnds ]
+       deprecs = case mod_deprec of
+          Nothing -> deprec_sigs
+          Just txt -> Deprecation (IEModuleContents undefined) txt : deprec_sigs
     in
 
        -- EXIT IF ERRORS FOUND
@@ -135,7 +147,7 @@ rename this_mod@(HsModule mod_name vers _ imports local_decls loc)
     getNameSupplyRn                            `thenRn` \ name_supply ->
 
        -- REPORT UNUSED NAMES
-    reportUnusedNames gbl_env global_avail_env
+    reportUnusedNames mod_name gbl_env global_avail_env
                      export_env
                      source_fvs                        `thenRn_`
 
@@ -146,17 +158,22 @@ rename this_mod@(HsModule mod_name vers _ imports local_decls loc)
        renamed_module = HsModule mod_name vers 
                                  trashed_exports trashed_imports
                                  rn_all_decls
+                                 mod_deprec
                                  loc
     in
     rnDump rn_imp_decls        rn_all_decls            `thenRn` \ dump_action ->
     returnRn (Just (mkThisModule mod_name,
                    renamed_module, 
-                   (has_orphans, my_usages, export_env),
+                   (InterfaceDetails has_orphans my_usages export_env deprecs),
                    name_supply,
                    direct_import_mods), dump_action)
   where
     trashed_exports  = {-trace "rnSource:trashed_exports"-} Nothing
     trashed_imports  = {-trace "rnSource:trashed_imports"-} []
+
+    collectDeprecs EmptyBinds = []
+    collectDeprecs (ThenBinds x y) = collectDeprecs x ++ collectDeprecs y
+    collectDeprecs (MonoBind _ sigs _) = [ d | DeprecSig d _ <- sigs ]
 \end{code}
 
 @implicitFVs@ forces the renamer to slurp in some things which aren't
@@ -417,7 +434,7 @@ vars of the source program, and extracts from the decl the gate names.
 getGates source_fvs (SigD (IfaceSig _ ty _ _))
   = extractHsTyNames ty
 
-getGates source_fvs (TyClD (ClassDecl ctxt cls tvs _ sigs _ _ _ _ _ _))
+getGates source_fvs (TyClD (ClassDecl ctxt cls tvs _ sigs _ _ _ _ _ _ _))
   = (delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) sigs)
                       (map getTyVarName tvs)
      `addOneToNameSet` cls)
@@ -447,13 +464,13 @@ getGates source_fvs (TyClD (TyData _ ctxt tycon tvs cons _ _ _))
                       (map getTyVarName tvs)
     `addOneToNameSet` tycon
   where
-    get (ConDecl n tvs ctxt details _)
+    get (ConDecl n _ tvs ctxt details _)
        | n `elemNameSet` source_fvs
                -- If the constructor is method, get fvs from all its fields
        = delListFromNameSet (get_details details `plusFV` 
                              extractHsCtxtTyNames ctxt)
                             (map getTyVarName tvs)
-    get (ConDecl n tvs ctxt (RecCon fields) _)
+    get (ConDecl n _ tvs ctxt (RecCon fields) _)
                -- Even if the constructor isn't mentioned, the fields
                -- might be, as selectors.  They can't mention existentially
                -- bound tyvars (typechecker checks for that) so no need for 
@@ -511,19 +528,36 @@ getInstDeclGates other                                = emptyFVs
 %*********************************************************
 
 \begin{code}
-reportUnusedNames gbl_env avail_env (ExportEnv export_avails _ _) mentioned_names
+reportUnusedNames :: ModuleName -> GlobalRdrEnv -> AvailEnv -> ExportEnv -> NameSet -> RnMG ()
+reportUnusedNames mod_name gbl_env avail_env (ExportEnv export_avails _ _) mentioned_names
   = let
        used_names = mentioned_names `unionNameSets` availsToNameSet export_avails
 
        -- Now, a use of C implies a use of T,
        -- if C was brought into scope by T(..) or T(C)
        really_used_names = used_names `unionNameSets`
-         mkNameSet [ availName avail   
-                   | sub_name <- nameSetToList used_names,
-                     let avail = case lookupNameEnv avail_env sub_name of
-                           Just avail -> avail
-                           Nothing -> WARN( True, text "reportUnusedName: not in avail_env" <+> ppr sub_name )
-                                      Avail sub_name
+         mkNameSet [ availName parent_avail
+                   | sub_name <- nameSetToList used_names
+                   , isValOcc (getOccName sub_name)
+
+                       -- Usually, every used name will appear in avail_env, but there 
+                       -- is one time when it doesn't: tuples and other built in syntax.  When you
+                       -- write (a,b) that gives rise to a *use* of "(,)", so that the
+                       -- instances will get pulled in, but the tycon "(,)" isn't actually
+                       -- in scope.  Hence the isValOcc filter.
+                       --
+                       -- Also, (-x) gives rise to an implicit use of 'negate'; similarly, 
+                       --   3.5 gives rise to an implcit use of :%
+                       -- hence the isUserImportedName filter on the warning
+                     
+                   , let parent_avail 
+                           = case lookupNameEnv avail_env sub_name of
+                               Just avail -> avail
+                               Nothing -> WARN( isUserImportedName sub_name,
+                                                text "reportUnusedName: not in avail_env" <+> ppr sub_name )
+                                          Avail sub_name
+                     
+                   , case parent_avail of { AvailTC _ _ -> True; other -> False }
                    ]
 
        defined_names = mkNameSet (concat (rdrEnvElts gbl_env))
@@ -533,9 +567,73 @@ reportUnusedNames gbl_env avail_env (ExportEnv export_avails _ _) mentioned_name
        -- Filter out the ones only defined implicitly
        bad_locals = [n | n <- defined_but_not_used, isLocallyDefined             n]
        bad_imps   = [n | n <- defined_but_not_used, isUserImportedExplicitlyName n]
+
+       deprec_used deprec_env = [ (n,txt)
+                                 | n <- nameSetToList mentioned_names,
+                                   not (isLocallyDefined n),
+                                   Just txt <- [lookupNameEnv deprec_env n] ]
+
+       minimal_imports :: FiniteMap Module AvailEnv
+       minimal_imports = foldNameSet add emptyFM really_used_names
+       add n acc = case maybeUserImportedFrom n of
+                       Nothing -> acc
+                       Just m  -> addToFM_C plusAvailEnv acc m
+                                            (unitAvailEnv (mk_avail n))
+       mk_avail n = case lookupNameEnv avail_env n of
+                       Just (AvailTC m _) | n==m      -> AvailTC n [n]
+                                          | otherwise -> AvailTC m [n,m]
+                       Just avail         -> Avail n
+                       Nothing            -> pprPanic "mk_avail" (ppr n)
     in
-    warnUnusedLocalBinds bad_locals    `thenRn_`
-    warnUnusedImports bad_imps
+    warnUnusedLocalBinds bad_locals                            `thenRn_`
+    warnUnusedImports bad_imps                                 `thenRn_`
+    printMinimalImports mod_name minimal_imports               `thenRn_`
+    getIfacesRn                                                        `thenRn` \ ifaces ->
+    (if opt_WarnDeprecations
+       then mapRn_ warnDeprec (deprec_used (iDeprecs ifaces))
+       else returnRn ())
+
+-- ToDo: deal with original imports with 'qualified' and 'as M' clauses
+printMinimalImports mod_name imps
+  | not opt_D_dump_minimal_imports
+  = returnRn ()
+  | otherwise
+  = mapRn to_ies (fmToList imps)               `thenRn` \ mod_ies ->
+    ioToRnM (do { h <- openFile filename WriteMode ;
+                 printForUser h (vcat (map ppr_mod_ie mod_ies))
+       })                                      `thenRn_`
+    returnRn ()
+  where
+    filename = moduleNameUserString mod_name ++ ".imports"
+    ppr_mod_ie (mod_name, ies) 
+       | mod_name == pRELUDE_Name 
+       = empty
+       | otherwise
+       = ptext SLIT("import") <+> ppr mod_name <> 
+                           parens (fsep (punctuate comma (map ppr ies)))
+
+    to_ies (mod, avail_env) = mapRn to_ie (availEnvElts avail_env)     `thenRn` \ ies ->
+                             returnRn (moduleName mod, ies)
+
+    to_ie :: AvailInfo -> RnMG (IE Name)
+    to_ie (Avail n)       = returnRn (IEVar n)
+    to_ie (AvailTC n [m]) = ASSERT( n==m ) 
+                           returnRn (IEThingAbs n)
+    to_ie (AvailTC n ns)  = getInterfaceExports (moduleName (nameModule n)) 
+                                               ImportBySystem          `thenRn` \ (_, avails) ->
+                           case [ms | AvailTC m ms <- avails, m == n] of
+                             [ms] | all (`elem` ns) ms -> returnRn (IEThingAll n)
+                                  | otherwise          -> returnRn (IEThingWith n (filter (/= n) ns))
+                             other -> pprTrace "to_ie" (ppr n <+> ppr (nameModule n) <+> ppr other) $
+                                      returnRn (IEVar n)
+
+warnDeprec :: (Name, DeprecTxt) -> RnM d ()
+warnDeprec (name, txt)
+  = pushSrcLocRn (getSrcLoc name)      $
+    addWarnRn                          $
+    sep [ text (occNameFlavour (nameOccName name)) <+> ppr name <+>
+          text "is deprecated:", nest 4 (ppr txt) ]
+
 
 rnDump  :: [RenamedHsDecl]     -- Renamed imported decls
        -> [RenamedHsDecl]      -- Renamed local decls
@@ -564,7 +662,7 @@ getRnStats :: [RenamedHsDecl] -> RnMG SDoc
 getRnStats imported_decls
   = getIfacesRn                `thenRn` \ ifaces ->
     let
-       n_mods = length [() | (_, _, Just _) <- eltsFM (iImpModInfo ifaces)]
+       n_mods = length [() | (_, _, _, Just _) <- eltsFM (iImpModInfo ifaces)]
 
        decls_read     = [decl | (_, avail, True, (_,decl)) <- nameEnvElts (iDecls ifaces),
                                -- Data, newtype, and class decls are in the decls_fm