[project @ 2005-05-05 00:58:38 by sof]
[ghc-hetmet.git] / ghc / compiler / rename / RnNames.lhs
index 8a8cc32..2cc62f8 100644 (file)
@@ -6,8 +6,9 @@
 \begin{code}
 module RnNames (
        rnImports, importsFromLocalDecls, 
+       getLocalDeclBinders, extendRdrEnvRn,
        reportUnusedNames, reportDeprecations, 
-       mkModDeps, exportsToAvails, exportsFromAvail
+       mkModDeps, exportsFromAvail
     ) where
 
 #include "HsVersions.h"
@@ -18,7 +19,7 @@ import HsSyn          ( IE(..), ieName, ImportDecl(..), LImportDecl,
                          Sig(..), collectGroupBinders, tyClDeclNames 
                        )
 import RnEnv
-import IfaceEnv                ( lookupAvail )
+import IfaceEnv                ( ifaceExportNames )
 import LoadIface       ( loadSrcInterface )
 import TcRnMonad
 
@@ -34,8 +35,8 @@ import NameEnv
 import OccName         ( srcDataName, isTcOcc, occNameFlavour, OccEnv, 
                          mkOccEnv, lookupOccEnv, emptyOccEnv, extendOccEnv )
 import HscTypes                ( GenAvailInfo(..), AvailInfo,
-                         IfaceExport, HomePackageTable, PackageIfaceTable, 
-                         availNames, unQualInScope, 
+                         HomePackageTable, PackageIfaceTable, 
+                         unQualInScope, 
                          Deprecs(..), ModIface(..), Dependencies(..), 
                          lookupIface, ExternalPackageState(..)
                        )
@@ -43,16 +44,16 @@ import Packages             ( PackageIdH(..) )
 import RdrName         ( RdrName, rdrNameOcc, setRdrNameSpace, 
                          GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..), 
                          emptyGlobalRdrEnv, plusGlobalRdrEnv, globalRdrEnvElts,
-                         unQualOK, lookupGRE_Name,
+                         extendGlobalRdrEnv, lookupGlobalRdrEnv, unQualOK, lookupGRE_Name,
                          Provenance(..), ImportSpec(..), 
                          isLocalGRE, pprNameProvenance )
 import Outputable
 import Maybes          ( isNothing, catMaybes, mapCatMaybes, seqMaybe, orElse )
 import SrcLoc          ( Located(..), mkGeneralSrcSpan,
-                         unLoc, noLoc, srcLocSpan, combineSrcSpans, SrcSpan )
+                         unLoc, noLoc, srcLocSpan, SrcSpan )
 import BasicTypes      ( DeprecTxt )
-import ListSetOps      ( removeDups )
-import Util            ( sortLe, notNull, isSingleton )
+import DriverPhases    ( isHsBoot )
+import Util            ( notNull )
 import List            ( partition )
 import IO              ( openFile, IOMode(..) )
 \end{code}
@@ -180,10 +181,10 @@ importsFromImportDecl this_mod
                          Nothing           -> imp_mod_name
                          Just another_name -> another_name
        imp_spec  = ImportSpec { is_mod = imp_mod_name, is_qual = qual_only,  
-                                is_loc = loc, is_as = qual_mod_name }
+                                is_loc = loc, is_as = qual_mod_name, is_explicit = False }
     in
        -- Get the total imports, and filter them according to the import list
-    exportsToAvails filtered_exports           `thenM` \ total_avails ->
+    ifaceExportNames filtered_exports          `thenM` \ total_avails ->
     filterImports iface imp_spec
                  imp_details total_avails      `thenM` \ (avail_env, gbl_env) ->
 
@@ -246,14 +247,6 @@ importsFromImportDecl this_mod
 
     returnM (gbl_env, imports)
 
-exportsToAvails :: [IfaceExport] -> TcRnIf gbl lcl NameSet
-exportsToAvails exports 
-  = foldlM do_one emptyNameSet exports
-  where
-    do_one acc (mod, exports)  = foldlM (do_avail mod) acc exports
-    do_avail mod acc avail = do { ns <- lookupAvail mod avail
-                               ; return (addListToNameSet acc ns) }
-
 warnRedundantSourceImport mod_name
   = ptext SLIT("Unnecessary {- SOURCE -} in the import of module")
           <+> quotes (ppr mod_name)
@@ -274,32 +267,14 @@ created by its bindings.
 Complain about duplicate bindings
 
 \begin{code}
-importsFromLocalDecls :: HsGroup RdrName
-                     -> RnM (GlobalRdrEnv, ImportAvails)
+importsFromLocalDecls :: HsGroup RdrName -> RnM TcGblEnv
 importsFromLocalDecls group
-  = getModule                          `thenM` \ this_mod ->
-    getLocalDeclBinders this_mod group `thenM` \ avails ->
-       -- The avails that are returned don't include the "system" names
-    let
-       all_names :: [Name]     -- All the defns; no dups eliminated
-       all_names = [name | avail <- avails, name <- availNames avail]
+  = do { gbl_env  <- getGblEnv
 
-       dups :: [[Name]]
-       (_, dups) = removeDups compare all_names
-    in
-       -- Check for duplicate definitions
-       -- The complaint will come out as "Multiple declarations of Foo.f" because
-       -- since 'f' is in the env twice, the unQualInScope used by the error-msg
-       -- printer returns False.  It seems awkward to fix, unfortunately.
-    mappM_ addDupDeclErr dups                  `thenM_` 
-
-    doptM Opt_ImplicitPrelude          `thenM` \ implicit_prelude ->
-    let
-       prov     = LocalDef this_mod
-       gbl_env  = mkGlobalRdrEnv gres
-       gres     = [ GRE { gre_name = name, gre_prov = prov}
-                  | name <- all_names]
+       ; names <- getLocalDeclBinders gbl_env group
 
+       ; implicit_prelude <- doptM Opt_ImplicitPrelude
+       ; let {
            -- Optimisation: filter out names for built-in syntax
            -- They just clutter up the environment (esp tuples), and the parser
            -- will generate Exact RdrNames for them, so the cluttered
@@ -318,24 +293,42 @@ importsFromLocalDecls group
            -- Ditto in fixity decls; e.g.      infix 5 :
            -- Sigh. It doesn't matter because it only affects the Data.Tuple really.
            -- The important thing is to trim down the exports.
-       filtered_names 
-         | implicit_prelude = all_names
-         | otherwise        = filter (not . isBuiltInSyntax) all_names
+             filtered_names 
+               | implicit_prelude = names
+               | otherwise        = filter (not . isBuiltInSyntax) names ;
 
-       imports = emptyImportAvails {
-                       imp_env = unitModuleEnv this_mod $
+           ; this_mod = tcg_mod gbl_env
+           ; imports = emptyImportAvails {
+                         imp_env = unitModuleEnv this_mod $
                                  mkNameSet filtered_names
-                   }
-    in
-    returnM (gbl_env, imports)
-\end{code}
+                       }
+           }
 
+       ; rdr_env' <- extendRdrEnvRn this_mod (tcg_rdr_env gbl_env) names
 
-%*********************************************************
-%*                                                     *
-\subsection{Getting binders out of a declaration}
-%*                                                     *
-%*********************************************************
+       ; returnM (gbl_env { tcg_rdr_env = rdr_env',
+                            tcg_imports = imports `plusImportAvails` tcg_imports gbl_env }) 
+       }
+
+extendRdrEnvRn :: Module -> GlobalRdrEnv -> [Name] -> RnM GlobalRdrEnv
+-- Add the new locally-bound names one by one, checking for duplicates as
+-- we do so.  Remember that in Template Haskell the duplicates
+-- might *already be* in the GlobalRdrEnv from higher up the module
+extendRdrEnvRn mod rdr_env names
+  = foldlM add_local rdr_env names
+  where
+    add_local rdr_env name
+       | gres <- lookupGlobalRdrEnv rdr_env (nameOccName name)
+       , (dup_gre:_) <- filter isLocalGRE gres -- Check for existing *local* defns
+       = do { addDupDeclErr (gre_name dup_gre) name
+            ; return rdr_env }
+       | otherwise
+       = return (extendGlobalRdrEnv rdr_env new_gre)
+       where
+         new_gre = GRE {gre_name = name, gre_prov = prov}
+
+    prov = LocalDef mod
+\end{code}
 
 @getLocalDeclBinders@ returns the names for an @HsDecl@.  It's
 used for source code.
@@ -343,27 +336,21 @@ used for source code.
        *** See "THE NAMING STORY" in HsDecls ****
 
 \begin{code}
-getLocalDeclBinders :: Module -> HsGroup RdrName -> RnM [AvailInfo]
-getLocalDeclBinders mod (HsGroup {hs_valds = val_decls, 
-                                 hs_tyclds = tycl_decls, 
-                                 hs_fords = foreign_decls })
-  =    -- For type and class decls, we generate Global names, with
-       -- no export indicator.  They need to be global because they get
-       -- permanently bound into the TyCons and Classes.  They don't need
-       -- an export indicator because they are all implicitly exported.
-
-    mappM new_tc     tycl_decls                                `thenM` \ tc_avails ->
-       
+getLocalDeclBinders :: TcGblEnv -> HsGroup RdrName -> RnM [Name]
+getLocalDeclBinders gbl_env (HsGroup {hs_valds = val_decls, 
+                                     hs_tyclds = tycl_decls, 
+                                     hs_fords = foreign_decls })
+  = do { tc_names_s <- mappM new_tc tycl_decls
+       ; val_names  <- mappM new_simple val_bndrs
+       ; return (foldr (++) val_names tc_names_s) }
+  where
+    mod        = tcg_mod gbl_env
+    is_hs_boot = isHsBoot (tcg_src gbl_env) ;
+    val_bndrs | is_hs_boot = sig_hs_bndrs
+             | otherwise  = for_hs_bndrs ++ val_hs_bndrs
        -- In a hs-boot file, the value binders come from the
        --  *signatures*, and there should be no foreign binders 
-    tcIsHsBoot                                         `thenM` \ is_hs_boot ->
-    let val_bndrs | is_hs_boot = sig_hs_bndrs
-                 | otherwise  = for_hs_bndrs ++ val_hs_bndrs
-    in
-    mappM new_simple val_bndrs                         `thenM` \ names ->
 
-    returnM (tc_avails ++ map Avail names)
-  where
     new_simple rdr_name = newTopSrcBinder mod Nothing rdr_name
 
     sig_hs_bndrs = [nm | HsBindGroup _ lsigs _  <- val_decls, 
@@ -372,9 +359,9 @@ getLocalDeclBinders mod (HsGroup {hs_valds = val_decls,
     for_hs_bndrs = [nm | L _ (ForeignImport nm _ _ _) <- foreign_decls]
 
     new_tc tc_decl 
-       = newTopSrcBinder mod Nothing main_rdr                  `thenM` \ main_name ->
-         mappM (newTopSrcBinder mod (Just main_name)) sub_rdrs `thenM` \ sub_names ->
-         returnM (AvailTC main_name (main_name : sub_names))
+       = do { main_name <- newTopSrcBinder mod Nothing main_rdr
+            ; sub_names <- mappM (newTopSrcBinder mod (Just main_name)) sub_rdrs
+            ; return (main_name : sub_names) }
        where
          (main_rdr : sub_rdrs) = tyClDeclNames (unLoc tc_decl)
 \end{code}
@@ -401,7 +388,7 @@ filterImports :: ModIface
         -- Warns/informs if import spec contains duplicates.
                        
 mkGenericRdrEnv imp_spec names
-  = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] False }
+  = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] }
                   | name <- nameSetToList names ]
 
 filterImports iface imp_spec Nothing all_names
@@ -441,9 +428,10 @@ filterImports iface imp_spec (Just (want_hiding, import_items)) all_names
           ; returnM (map (mk_gre loc) names) }
       where
        mk_gre loc name = GRE { gre_name = name, 
-                               gre_prov = Imported [this_imp_spec loc] (explicit name) }
-       this_imp_spec loc = imp_spec { is_loc = loc }
-       explicit name = all_explicit || isNothing (nameParent_maybe name)
+                               gre_prov = Imported [imp_spec'] }
+         where
+           imp_spec' = imp_spec { is_loc = loc, is_explicit = explicit }
+           explicit = all_explicit || isNothing (nameParent_maybe name)
 
     get_item :: IE RdrName -> RnM [GlobalRdrElt]
        -- Empty result for a bad item.
@@ -614,6 +602,7 @@ filterAvail (IEThingWith _ rdrs) n subs
   where
     env = mkOccEnv [(nameOccName s, s) | s <- subNames subs n]
     mb_names = map (lookupOccEnv env . rdrNameOcc) rdrs
+filterAvail (IEModuleContents _) _ _ = panic "filterAvail"
 
 subNames :: NameEnv [Name] -> Name -> [Name]
 subNames env n = lookupNameEnv env n `orElse` []
@@ -685,7 +674,7 @@ reportDeprecations tcg_env
     used_names = findUses (tcg_dus tcg_env) emptyNameSet
     all_gres   = globalRdrEnvElts (tcg_rdr_env tcg_env)
 
-    check hpt pit (GRE {gre_name = name, gre_prov = Imported (imp_spec:_) _})
+    check hpt pit (GRE {gre_name = name, gre_prov = Imported (imp_spec:_)})
       | name `elemNameSet` used_names
       ,        Just deprec_txt <- lookupDeprec hpt pit name
       = setSrcSpan (is_loc imp_spec) $
@@ -741,7 +730,7 @@ reportUnusedNames export_decls gbl_env
   = do { warnUnusedTopBinds   unused_locals
        ; warnUnusedModules    unused_imp_mods
        ; warnUnusedImports    unused_imports   
-       ; warnDuplicateImports dup_imps
+       ; warnDuplicateImports defined_and_used
        ; printMinimalImports  minimal_imports }
   where
     used_names, all_used_names :: NameSet
@@ -762,11 +751,6 @@ reportUnusedNames export_decls gbl_env
     (defined_and_used, defined_but_not_used) 
        = partition (gre_is_used all_used_names) defined_names
     
-       -- Find the duplicate imports
-    dup_imps = filter is_dup defined_and_used
-    is_dup (GRE {gre_prov = Imported imp_spec True}) = not (isSingleton imp_spec)
-    is_dup other                                    = False
-
        -- Filter out the ones that are 
        --  (a) defined in this module, and
        --  (b) not defined by a 'deriving' clause 
@@ -778,8 +762,9 @@ reportUnusedNames export_decls gbl_env
     
     unused_imports :: [GlobalRdrElt]
     unused_imports = filter unused_imp defined_but_not_used
-    unused_imp (GRE {gre_prov = Imported imp_specs True}) 
+    unused_imp (GRE {gre_prov = Imported imp_specs}) 
        = not (all (module_unused . is_mod) imp_specs)
+         && any is_explicit imp_specs
                -- Don't complain about unused imports if we've already said the
                -- entire import is unused
     unused_imp other = False
@@ -811,7 +796,7 @@ reportUnusedNames export_decls gbl_env
        -- We've carefully preserved the provenance so that we can
        -- construct minimal imports that import the name by (one of)
        -- the same route(s) as the programmer originally did.
-    add_name (GRE {gre_name = n, gre_prov = Imported imp_specs _}) acc 
+    add_name (GRE {gre_name = n, gre_prov = Imported imp_specs}) acc 
        = addToFM_C plusAvailEnv acc (is_mod (head imp_specs))
                    (unitAvailEnv (mk_avail n (nameParent_maybe n)))
     add_name other acc 
@@ -876,13 +861,65 @@ reportUnusedNames export_decls gbl_env
 
 ---------------------
 warnDuplicateImports :: [GlobalRdrElt] -> RnM ()
+-- Given the GREs for names that are used, figure out which imports 
+-- could be omitted without changing the top-level environment.
+--
+-- NB: Given import Foo( T )
+--                  import qualified Foo
+-- we do not report a duplicate import, even though Foo.T is brought
+-- into scope by both, because there's nothing you can *omit* without
+-- changing the top-level environment.  So we complain only if it's
+-- explicitly named in both imports or neither.
+--
+-- Furthermore, we complain about Foo.T only if 
+-- there is no complaint about (unqualified) T
+
 warnDuplicateImports gres
-  = ifOptM Opt_WarnUnusedImports (mapM_ warn gres)
+  = ifOptM Opt_WarnUnusedImports $ 
+    sequenceM_ [ warn name pr
+                       -- The 'head' picks the first offending group
+                       -- for this particular name
+               | GRE { gre_name = name, gre_prov = Imported imps } <- gres
+               , pr <- redundants imps ]
   where
-    warn (GRE { gre_name = name, gre_prov = Imported imps _ })
-       = addWarn ((quotes (ppr name) <+> ptext SLIT("is imported more than once:")) 
-              $$ nest 2 (vcat (map ppr imps)))
-                             
+    warn name (red_imp, cov_imp)
+       = addWarnAt (is_loc red_imp)
+           (vcat [ptext SLIT("Redundant import of:") <+> quotes pp_name,
+                  ptext SLIT("It is also") <+> ppr cov_imp])
+       where
+         pp_name | is_qual red_imp = ppr (is_as red_imp) <> dot <> ppr occ
+                 | otherwise       = ppr occ
+         occ = nameOccName name
+    
+    redundants :: [ImportSpec] -> [(ImportSpec,ImportSpec)]
+       -- The returned pair is (redundant-import, covering-import)
+    redundants imps 
+       = [ (red_imp, cov_imp) 
+         | red_imp <- imps
+         , cov_imp <- take 1 (filter (covers red_imp) imps) ]
+
+       -- "red_imp" is a putative redundant import
+       -- "cov_imp" potentially covers it
+       -- This test decides
+    covers red_imp cov_imp
+       | red_loc == cov_loc
+       = False         -- Ignore diagonal elements
+       | not (is_as red_imp == is_as cov_imp)
+       = False         -- They bring into scope different qualified names
+       | not (is_qual red_imp) && is_qual cov_imp
+       = False         -- Covering one doesn't bring unqualified name into scope
+       | is_explicit red_imp   
+       = not cov_explicit      -- Redundant one is explicit and covering one isn't
+         || red_later          -- Both are explicit; tie-break using red_later
+       | otherwise             
+       = not cov_explicit      -- Neither import is explicit
+         && (is_mod red_imp == is_mod cov_imp) -- They import the same module
+         && red_later          -- Tie-break
+       where
+         cov_explicit = is_explicit cov_imp
+         red_loc   = is_loc red_imp
+         cov_loc   = is_loc cov_imp
+         red_later = red_loc > cov_loc
 
 -- ToDo: deal with original imports with 'qualified' and 'as M' clauses
 printMinimalImports :: FiniteMap Module AvailEnv       -- Minimal imports
@@ -979,16 +1016,13 @@ exportClashErr global_env name1 name2 ie1 ie2
             (gre:_) -> gre
             []      -> pprPanic "exportClashErr" (ppr name)
 
-addDupDeclErr :: [Name] -> TcRn ()
-addDupDeclErr names
-  = addErrAt big_loc $
+addDupDeclErr :: Name -> Name -> TcRn ()
+addDupDeclErr name1 name2
+  = addErrAt (srcLocSpan loc2) $
     vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr name1),
-         ptext SLIT("Declared at:") <+> vcat (map ppr sorted_locs)]
+         ptext SLIT("Declared at:") <+> vcat [ppr (nameSrcLoc name1), ppr loc2]]
   where
-    locs    = map nameSrcLoc names
-    big_loc = foldr1 combineSrcSpans (map srcLocSpan locs)
-    name1   = head names
-    sorted_locs = sortLe (<=) (sortLe (<=) locs)
+    loc2    = nameSrcLoc name2
 
 dupExportWarn occ_name ie1 ie2
   = hsep [quotes (ppr occ_name),