[project @ 2001-12-07 17:33:26 by simonpj]
authorsimonpj <unknown>
Fri, 7 Dec 2001 17:33:26 +0000 (17:33 +0000)
committersimonpj <unknown>
Fri, 7 Dec 2001 17:33:26 +0000 (17:33 +0000)
----------------------------
More jiggling in the renamer
----------------------------

I was a little hasty before.  (Thanks Sigbjorn for finding
this.)  This commit tidies up the handling of AvailEnvs.
Principally:

  * filterImports now deals completely with hiding
    (before it handed off part of the job to mkGlobalRdrEnv)

  * The AvailEnv in an ExportAvails does not have class ops and
    data constructors in its domain.  This makes plusExportAvails
    more efficient, but the main thing is that it collects things
    up right.  (Previously, if we had
import M( C )
import M( op )
    then we got an AvailEnv which had C |-> AvailTC C [C]
    (no 'op').

  * In Rename, we do need a "filled-out" version of the overall
    AvailEnv, full_avail_env, which we construct on the spot in 'rename'.

ghc/compiler/rename/Rename.lhs
ghc/compiler/rename/RnEnv.lhs
ghc/compiler/rename/RnMonad.lhs
ghc/compiler/rename/RnNames.lhs

index 413e9b3..873b758 100644 (file)
@@ -34,7 +34,7 @@ import RnHiFiles      ( readIface, loadInterface,
                          loadExports, loadFixDecls, loadDeprecs,
                        )
 import RnEnv           ( availsToNameSet, mkIfaceGlobalRdrEnv,
-                         unitAvailEnv, availEnvElts, 
+                         unitAvailEnv, availEnvElts, availNames,
                          plusAvailEnv, groupAvails, warnUnusedImports, 
                          warnUnusedLocalBinds, warnUnusedModules, 
                          lookupSrcName, getImplicitStmtFVs, 
@@ -243,9 +243,25 @@ rename this_module contents@(HsModule _ _ exports imports local_decls mod_deprec
   = pushSrcLocRn loc           $
 
        -- FIND THE GLOBAL NAME ENVIRONMENT
-    getGlobalNames this_module contents        `thenRn` \ (gbl_env, local_gbl_env, all_avails@(_, global_avail_env)) ->
+    getGlobalNames this_module contents                `thenRn` \ (gbl_env, local_gbl_env, 
+                                                           (mod_avail_env, global_avail_env)) ->
     let
        print_unqualified = unQualInScope gbl_env
+
+       full_avail_env :: NameEnv AvailInfo
+               -- The domain of global_avail_env is just the 'major' things;
+               -- variables, type constructors, classes.  
+               --      E.g. Functor |-> Functor( Functor, fmap )
+               -- The domain of full_avail_env is everything in scope
+               --      E.g. Functor |-> Functor( Functor, fmap )
+               --           fmap    |-> Functor( Functor, fmap )
+               -- 
+               -- This filled-out avail_env is needed to generate
+               -- exports (mkExportAvails), and for generating minimal
+               -- exports (reportUnusedNames)
+       full_avail_env = mkNameEnv [ (name,avail) 
+                                  | avail <- availEnvElts global_avail_env,
+                                    name  <- availNames avail]
     in
        -- Exit if we've found any errors
     checkErrsRn                                `thenRn` \ no_errs_so_far ->
@@ -256,7 +272,8 @@ rename this_module contents@(HsModule _ _ exports imports local_decls mod_deprec
     else
        
        -- PROCESS EXPORT LIST 
-    exportsFromAvail mod_name exports all_avails gbl_env       `thenRn` \ export_avails ->
+    exportsFromAvail mod_name exports mod_avail_env 
+                    full_avail_env gbl_env             `thenRn` \ export_avails ->
        
     traceRn (text "Local top-level environment" $$ 
             nest 4 (pprGlobalRdrEnv local_gbl_env))    `thenRn_`
@@ -340,7 +357,7 @@ rename this_module contents@(HsModule _ _ exports imports local_decls mod_deprec
 
        -- REPORT UNUSED NAMES, AND DEBUG DUMP 
     reportUnusedNames mod_iface print_unqualified 
-                     imports global_avail_env
+                     imports full_avail_env
                      source_fvs2 rn_imp_decls          `thenRn_`
                -- NB: source_fvs2: include exports (else we get bogus 
                --     warnings of unused things) but not implicit FVs.
@@ -763,7 +780,8 @@ printMinimalImports this_mod unqual imps
     to_ie (AvailTC n [m]) = ASSERT( n==m ) 
                            returnRn (IEThingAbs n)
     to_ie (AvailTC n ns)  
-       = loadInterface (text "Compute minimal imports from" <+> ppr n_mod) n_mod ImportBySystem        `thenRn` \ iface ->
+       = loadInterface (text "Compute minimal imports from" <+> ppr n_mod) 
+                       n_mod ImportBySystem                            `thenRn` \ iface ->
          case [xs | (m,as) <- mi_exports iface,
                     m == n_mod,
                     AvailTC x xs <- as, 
index affbcc9..25307f2 100644 (file)
@@ -56,6 +56,7 @@ import Util           ( sortLt )
 import BasicTypes      ( mapIPName )
 import List            ( nub )
 import UniqFM          ( lookupWithDefaultUFM )
+import Maybe           ( mapMaybe )
 import CmdLineOpts
 import FastString      ( FastString )
 \end{code}
@@ -258,8 +259,10 @@ lookupInstDeclBndr cls_name rdr_name
   | otherwise  
   = getGlobalAvails    `thenRn` \ avail_env ->
     case lookupNameEnv avail_env cls_name of
-         -- class not in scope; don't fail as later checks will catch this,
-         -- but just return (bogus) name. Icky.
+         -- The class itself isn't in scope, so cls_name is unboundName
+         -- e.g.   import Prelude hiding( Ord )
+         --        instance Ord T where ...
+         -- The program is wrong, but that should not cause a crash.
        Nothing -> returnRn (mkUnboundName rdr_name)
        Just (AvailTC _ ns) -> case [n | n <- ns, nameOccName n == occ] of
                                (n:ns)-> ASSERT( null ns ) returnRn n
@@ -681,13 +684,11 @@ mkGlobalRdrEnv :: ModuleName              -- Imported module (after doing the "as M" name ch
               -> Bool                  -- True <=> want unqualified import
               -> (Name -> Provenance)
               -> Avails                -- Whats imported
-              -> Avails                -- What's to be hidden
-                                       -- I.e. import (imports - hides)
               -> Deprecations
               -> GlobalRdrEnv
 
-mkGlobalRdrEnv this_mod unqual_imp mk_provenance avails hides deprecs
-  = gbl_env3
+mkGlobalRdrEnv this_mod unqual_imp mk_provenance avails deprecs
+  = gbl_env2
   where
        -- Make the name environment.  We're talking about a 
        -- single module here, so there must be no name clashes.
@@ -698,12 +699,9 @@ mkGlobalRdrEnv this_mod unqual_imp mk_provenance avails hides deprecs
        -- (Qualified names are always imported)
     gbl_env1 = foldl add_avail emptyRdrEnv avails
 
-       -- Delete (qualified names of) things that are hidden
-    gbl_env2 = foldl del_avail gbl_env1 hides
-
        -- Add unqualified names
-    gbl_env3 | unqual_imp = foldl add_unqual gbl_env2 (rdrEnvToList gbl_env2)
-            | otherwise  = gbl_env2
+    gbl_env2 | unqual_imp = foldl add_unqual gbl_env1 (rdrEnvToList gbl_env1)
+            | otherwise  = gbl_env1
 
     add_unqual env (qual_name, elts)
        = foldl add_one env elts
@@ -715,13 +713,6 @@ mkGlobalRdrEnv this_mod unqual_imp mk_provenance avails hides deprecs
        -- the module (multiple bindings for the same name) we may get
        -- duplicates.  So the simple thing is to do the fold.
 
-    del_avail env avail 
-       = foldl delOneFromGlobalRdrEnv env rdr_names
-       where
-         rdr_names = map (mkRdrQual this_mod . nameOccName)
-                         (availNames avail)
-
-
     add_avail :: GlobalRdrEnv -> AvailInfo -> GlobalRdrEnv
     add_avail env avail = foldl add_name env (availNames avail)
 
@@ -740,7 +731,7 @@ mkIfaceGlobalRdrEnv m_avails
   = foldl add emptyRdrEnv m_avails
   where
     add env (mod,avails) = plusGlobalRdrEnv env (mkGlobalRdrEnv mod True 
-                                                               (\n -> LocalDef) avails [] NoDeprecs)
+                                                               (\n -> LocalDef) avails NoDeprecs)
                -- The NoDeprecs is a bit of a hack I suppose
 \end{code}
 
@@ -793,8 +784,12 @@ in error messages.
 
 \begin{code}
 unQualInScope :: GlobalRdrEnv -> Name -> Bool
--- True if 'f' is in scope, and has only one binding
+-- True if 'f' is in scope, and has only one binding,
+-- and the thing it is bound to is the name we are looking for
 -- (i.e. false if A.f and B.f are both in scope as unqualified 'f')
+--
+-- This fn is only efficient if the shared 
+-- partial application is used a lot.
 unQualInScope env
   = (`elemNameSet` unqual_names)
   where
@@ -919,6 +914,21 @@ sortAvail (AvailTC n ns) | n `elem` ns = AvailTC n (n : sortLt lt (filter (/= n)
                           n1 `lt` n2 = nameOccName n1 < nameOccName n2
 \end{code}
 
+\begin{code}
+pruneAvails :: (Name -> Bool)  -- Keep if this is True
+           -> [AvailInfo]
+           -> [AvailInfo]
+pruneAvails keep avails
+  = mapMaybe del avails
+  where
+    del :: AvailInfo -> Maybe AvailInfo        -- Nothing => nothing left!
+    del (Avail n) | keep n    = Just (Avail n)
+                 | otherwise = Nothing
+    del (AvailTC n ns) | null ns'  = Nothing
+                      | otherwise = Just (AvailTC n ns')
+                      where
+                        ns' = filter keep ns
+\end{code}
 
 %************************************************************************
 %*                                                                     *
index 495b50f..809e3f6 100644 (file)
@@ -202,14 +202,6 @@ lookupLocalFixity env name
        Nothing                  -> defaultFixity
 \end{code}
 
-\begin{code}
-type ExportAvails = (FiniteMap ModuleName Avails,
-       -- Used to figure out "module M" export specifiers
-       -- Includes avails only from *unqualified* imports
-       -- (see 1.4 Report Section 5.1.1)
-
-                    AvailEnv)  -- Used to figure out all other export specifiers.
-\end{code}
 
 %===================================================
 \subsubsection{                INTERFACE FILE STUFF}
index 078863f..e5ce969 100644 (file)
@@ -5,7 +5,7 @@
 
 \begin{code}
 module RnNames (
-       getGlobalNames, exportsFromAvail
+       ExportAvails, getGlobalNames, exportsFromAvail
     ) where
 
 #include "HsVersions.h"
@@ -168,7 +168,7 @@ importsFromImportDecl this_mod_name (ImportDecl imp_mod_name from qual_only as_m
     )                                                  `thenRn_`
 
        -- Filter the imports according to the import list
-    filterImports imp_mod_name from import_spec avails `thenRn` \ (filtered_avails, hides, explicits) ->
+    filterImports imp_mod_name from import_spec avails `thenRn` \ (filtered_avails, explicits) ->
 
     let
        unqual_imp = not qual_only              -- Maybe want unqualified names
@@ -177,8 +177,8 @@ importsFromImportDecl this_mod_name (ImportDecl imp_mod_name from qual_only as_m
                        Just another_name -> another_name
 
        mk_prov name = NonLocalDef (UserImport imp_mod iloc (name `elemNameSet` explicits)) 
-       gbl_env      = mkGlobalRdrEnv qual_mod unqual_imp mk_prov filtered_avails hides deprecs
-       exports      = mkExportAvails qual_mod unqual_imp gbl_env hides filtered_avails
+       gbl_env      = mkGlobalRdrEnv qual_mod unqual_imp mk_prov filtered_avails deprecs
+       exports      = mkExportAvails qual_mod unqual_imp gbl_env filtered_avails
     in
     returnRn (gbl_env, exports)
 \end{code}
@@ -210,9 +210,8 @@ importsFromLocalDecls this_mod decls
        mod_name   = moduleName this_mod
        unqual_imp = True       -- Want unqualified names
        mk_prov n  = LocalDef   -- Provenance is local
-       hides      = []         -- Hide nothing
 
-       gbl_env    = mkGlobalRdrEnv mod_name unqual_imp mk_prov avails hides NoDeprecs
+       gbl_env    = mkGlobalRdrEnv mod_name unqual_imp mk_prov avails NoDeprecs
            -- NoDeprecs: don't complain about locally defined names
            -- For a start, we may be exporting a deprecated thing
            -- Also we may use a deprecated thing in the defn of another
@@ -220,7 +219,7 @@ importsFromLocalDecls this_mod decls
            -- the defn of a non-deprecated thing, when changing a module's 
            -- interface
 
-       exports    = mkExportAvails mod_name unqual_imp gbl_env hides avails
+       exports    = mkExportAvails mod_name unqual_imp gbl_env avails
     in
     returnRn (gbl_env, exports)
 
@@ -272,18 +271,13 @@ filterImports :: ModuleName                       -- The module being imported
              -> WhereFrom                      -- Tells whether it's a {-# SOURCE #-} import
              -> Maybe (Bool, [RdrNameIE])      -- Import spec; True => hiding
              -> [AvailInfo]                    -- What's available
-             -> RnMG ([AvailInfo],             -- "chosens"
-                      [AvailInfo],             -- "hides"
-                       -- The true imports are "chosens" - "hides"
-                       -- (It's convenient to return both the above sets, because
-                       --  the substraction can be done more efficiently when
-                       --  building the environment.)
+             -> RnMG ([AvailInfo],             -- What's imported
                       NameSet)                 -- What was imported explicitly
 
        -- Complains if import spec mentions things that the module doesn't export
         -- Warns/informs if import spec contains duplicates.
 filterImports mod from Nothing imports
-  = returnRn (imports, [], emptyNameSet)
+  = returnRn (imports, emptyNameSet)
 
 filterImports mod from (Just (want_hiding, import_items)) total_avails
   = flatMapRn get_item import_items            `thenRn` \ avails_w_explicits ->
@@ -291,13 +285,15 @@ filterImports mod from (Just (want_hiding, import_items)) total_avails
        (item_avails, explicits_s) = unzip avails_w_explicits
        explicits                  = foldl addListToNameSet emptyNameSet explicits_s
     in
-    if want_hiding 
-    then       
-       -- All imported; item_avails to be hidden
-       returnRn (total_avails, item_avails, emptyNameSet)
+    if want_hiding then
+       let     -- All imported; item_avails to be hidden
+          hidden = availsToNameSet item_avails
+          keep n = not (n `elemNameSet` hidden)
+       in
+       returnRn (pruneAvails keep total_avails, emptyNameSet)
     else
        -- Just item_avails imported; nothing to be hidden
-       returnRn (item_avails, [], explicits)
+       returnRn (item_avails, explicits)
   where
     import_fm :: FiniteMap OccName AvailInfo
     import_fm = listToFM [ (nameOccName name, avail) 
@@ -364,62 +360,38 @@ filterImports mod from (Just (want_hiding, import_items)) total_avails
 %************************************************************************
 
 \begin{code}
+type ExportAvails 
+   = (FiniteMap ModuleName Avails,
+               -- Used to figure out "module M" export specifiers
+               -- Includes avails only from *unqualified* imports
+               -- (see 1.4 Report Section 5.1.1)
+
+     AvailEnv) -- All the things that are available.
+               -- Its domain is all the "main" things;
+               -- i.e. *excluding* class ops and constructors
+               --      (which appear inside their parent AvailTC)
+
 mkEmptyExportAvails :: ModuleName -> ExportAvails
 mkEmptyExportAvails mod_name = (unitFM mod_name [], emptyNameEnv)
 
-mkExportAvails :: ModuleName -> Bool -> GlobalRdrEnv -> [AvailInfo] -> [AvailInfo] -> ExportAvails
-mkExportAvails mod_name unqual_imp gbl_env hides avails 
+plusExportAvails ::  ExportAvails ->  ExportAvails ->  ExportAvails
+plusExportAvails (m1, e1) (m2, e2) = (plusFM_C (++) m1 m2, plusAvailEnv e1 e2)
+
+mkExportAvails :: ModuleName -> Bool -> GlobalRdrEnv -> [AvailInfo] -> ExportAvails
+mkExportAvails mod_name unqual_imp gbl_env avails 
   = (mod_avail_env, entity_avail_env)
   where
     mod_avail_env = unitFM mod_name unqual_avails 
 
-       -- unqual_avails is the Avails that are visible in *unqualfied* form
-       -- (1.4 Report, Section 5.1.1)
-       -- For example, in 
-       --      import T hiding( f )
-       -- we delete f from avails
+       -- unqual_avails is the Avails that are visible in *unqualified* form
+       -- We need to know this so we know what to export when we see
+       --      module M ( module P ) where ...
+       -- Then we must export whatever came from P unqualified.
 
     unqual_avails | not unqual_imp = []        -- Short cut when no unqualified imports
-                 | otherwise      = mapMaybe prune avails
-
-    prune (Avail n) | unqual_in_scope n = Just (Avail n)
-                    | otherwise                = Nothing
-    prune (AvailTC n ns) | null uqs     = Nothing
-                        | otherwise    = Just (AvailTC n uqs)
-                        where
-                          uqs = filter unqual_in_scope ns
-
-    unqual_in_scope n = unQualInScope gbl_env n
-
+                 | otherwise      = pruneAvails (unQualInScope gbl_env) avails
 
-    entity_avail_env  = mkNameEnv ([ (availName avail,avail) | avail <- effective_avails ]  ++
-                                       -- sigh - need to have the method/field names in
-                                       -- the environment also, so that export lists
-                                       -- can be computed precisely (cf. exportsFromAvail)
-                                  [ (name,avail) | avail <- effective_avails,
-                                                   name  <- avNames avail ] )
-
-    avNames (Avail n) = [n]
-    avNames (AvailTC n ns) = filter (/=n) ns
-
-       -- remove 'hides' names from the avail list.
-    effective_avails = foldl wipeOut avails hides
-      where
-        wipeOut as (Avail n)       = mapMaybe (delName n) as
-       wipeOut as (AvailTC n ns)  = foldl wipeOut as (map Avail ns)
-
-       delName x a@(Avail n) 
-         | n == x    = Nothing
-          | otherwise = Just a
-       delName x (AvailTC n ns) 
-         = case (filter (/=x) ns) of
-             [] -> Nothing
-             xs -> Just (AvailTC n xs)
-
-plusExportAvails ::  ExportAvails ->  ExportAvails ->  ExportAvails
-plusExportAvails (m1, e1) (m2, e2)
-  = (plusFM_C (++) m1 m2, plusAvailEnv e1 e2)
-       -- ToDo: wasteful: we do this once for each constructor!
+    entity_avail_env  = mkNameEnv [(availName avail, avail) | avail <- avails]
 \end{code}
 
 
@@ -457,15 +429,17 @@ type ExportOccMap = FiniteMap OccName (Name, RdrNameIE)
 
 
 exportsFromAvail :: ModuleName
-                -> Maybe [RdrNameIE]   -- Export spec
-                -> ExportAvails
+                -> Maybe [RdrNameIE]           -- Export spec
+                -> FiniteMap ModuleName Avails -- Used for (module M) exports
+                -> NameEnv AvailInfo           -- Domain is every in-scope thing
                 -> GlobalRdrEnv 
                 -> RnMG Avails
        -- Complains if two distinct exports have same OccName
         -- Warns about identical exports.
        -- Complains about exports items not in scope
-exportsFromAvail this_mod Nothing export_avails global_name_env
-  = exportsFromAvail this_mod true_exports export_avails global_name_env
+exportsFromAvail this_mod Nothing 
+                mod_avail_env entity_avail_env global_name_env
+  = exportsFromAvail this_mod true_exports mod_avail_env entity_avail_env global_name_env
   where
     true_exports = Just $ if this_mod == mAIN_Name
                           then [IEVar main_RDR_Unqual]
@@ -474,8 +448,7 @@ exportsFromAvail this_mod Nothing export_avails global_name_env
                                -- but for all other modules export everything.
 
 exportsFromAvail this_mod (Just export_items) 
-                (mod_avail_env, entity_avail_env)
-                global_name_env
+                mod_avail_env entity_avail_env global_name_env
   = doptRn Opt_WarnDuplicateExports            `thenRn` \ warn_dup_exports ->
     foldlRn (exports_from_item warn_dup_exports)
            ([], emptyFM, emptyAvailEnv) export_items