[project @ 2006-01-06 16:30:17 by simonmar]
[ghc-hetmet.git] / ghc / compiler / rename / RnNames.lhs
index 4b5bb26..4cdb241 100644 (file)
@@ -6,37 +6,40 @@
 \begin{code}
 module RnNames (
        rnImports, importsFromLocalDecls, 
+       rnExports,
+       getLocalDeclBinders, extendRdrEnvRn,
        reportUnusedNames, reportDeprecations, 
-       mkModDeps, exportsToAvails, exportsFromAvail
+       mkModDeps
     ) where
 
 #include "HsVersions.h"
 
-import CmdLineOpts     ( DynFlag(..) )
+import DynFlags                ( DynFlag(..), GhcMode(..) )
 import HsSyn           ( IE(..), ieName, ImportDecl(..), LImportDecl,
-                         ForeignDecl(..), HsGroup(..), HsBindGroup(..), 
-                         Sig(..), collectGroupBinders, tyClDeclNames 
+                         ForeignDecl(..), HsGroup(..), HsValBinds(..),
+                         Sig(..), collectHsBindLocatedBinders, tyClDeclNames 
                        )
 import RnEnv
-import IfaceEnv                ( lookupOrig, newGlobalBinder )
+import IfaceEnv                ( ifaceExportNames )
 import LoadIface       ( loadSrcInterface )
 import TcRnMonad
 
 import FiniteMap
 import PrelNames       ( pRELUDE, isUnboundName, main_RDR_Unqual )
-import Module          ( Module, moduleUserString,
-                         unitModuleEnv, unitModuleEnv, 
+import Module          ( Module, moduleString, unitModuleEnv, 
                          lookupModuleEnv, moduleEnvElts, foldModuleEnv )
 import Name            ( Name, nameSrcLoc, nameOccName, nameModule, isWiredInName,
                          nameParent, nameParent_maybe, isExternalName,
                          isBuiltInSyntax )
 import NameSet
 import NameEnv
-import OccName         ( srcDataName, isTcOcc, occNameFlavour, OccEnv, 
-                         mkOccEnv, lookupOccEnv, emptyOccEnv, extendOccEnv )
-import HscTypes                ( GenAvailInfo(..), AvailInfo, GhciMode(..),
-                         IfaceExport, HomePackageTable, PackageIfaceTable, 
-                         availNames, unQualInScope, 
+import OccName         ( srcDataName, isTcOcc, pprNonVarNameSpace,
+                         occNameSpace,
+                         OccEnv, mkOccEnv, lookupOccEnv, emptyOccEnv,
+                         extendOccEnv )
+import HscTypes                ( GenAvailInfo(..), AvailInfo,
+                         HomePackageTable, PackageIfaceTable, 
+                         unQualInScope, 
                          Deprecs(..), ModIface(..), Dependencies(..), 
                          lookupIface, ExternalPackageState(..)
                        )
@@ -44,16 +47,16 @@ import Packages             ( PackageIdH(..) )
 import RdrName         ( RdrName, rdrNameOcc, setRdrNameSpace, 
                          GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..), 
                          emptyGlobalRdrEnv, plusGlobalRdrEnv, globalRdrEnvElts,
-                         unQualOK, lookupGRE_Name,
-                         Provenance(..), ImportSpec(..), 
-                         isLocalGRE, pprNameProvenance )
+                         extendGlobalRdrEnv, lookupGlobalRdrEnv, unQualOK, lookupGRE_Name,
+                         Provenance(..), ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..), 
+                         importSpecLoc, importSpecModule, isLocalGRE, pprNameProvenance )
 import Outputable
 import Maybes          ( isNothing, catMaybes, mapCatMaybes, seqMaybe, orElse )
-import SrcLoc          ( noSrcLoc, Located(..), mkGeneralSrcSpan,
-                         unLoc, noLoc, srcLocSpan, combineSrcSpans, SrcSpan )
+import SrcLoc          ( Located(..), mkGeneralSrcSpan,
+                         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,11 +183,11 @@ importsFromImportDecl this_mod
        qual_mod_name = case as_mod of
                          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 }
+       imp_spec  = ImpDeclSpec { is_mod = imp_mod_name, is_qual = qual_only,  
+                                 is_dloc = loc, is_as = qual_mod_name }
     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) ->
 
@@ -220,11 +223,10 @@ importsFromImportDecl this_mod
                 ASSERT2( not (pkg `elem` dep_pkgs deps), ppr pkg <+> ppr (dep_pkgs deps) )
                 ([], pkg : dep_pkgs deps)
 
+       -- True <=> import M ()
        import_all = case imp_details of
-                       Just (is_hiding, ls)     -- Imports are spec'd explicitly
-                         | not is_hiding -> Just (not (null ls))
-                       _ -> Nothing            -- Everything is imported, 
-                                               -- (or almost everything [hiding])
+                       Just (is_hiding, ls) -> not is_hiding && null ls        
+                       other                -> False
 
        -- 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
@@ -247,40 +249,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 n) = do { n' <- lookupOrig mod n; 
-                                   ; return (addOneToNameSet acc n') }
-    do_avail mod acc (AvailTC p_occ occs) 
-       = do { p_name <- lookupOrig mod p_occ
-            ; ns <- mappM (lookup_sub p_name) occs
-            ; return (addListToNameSet acc ns) }
-       -- Remember that 'occs' is all the exported things, including
-       -- the parent.  It's possible to export just class ops without
-       -- the class, via C( op ). If the class was exported too we'd
-       -- have C( C, op )
-       where
-          lookup_sub parent occ 
-               = newGlobalBinder mod occ mb_parent noSrcLoc
-               where
-                 mb_parent | occ == p_occ = Nothing
-                           | otherwise    = Just parent
-
-       -- The use of newGlobalBinder here (rather than lookupOrig) 
-       -- ensures that the subordinate names record their parent; 
-       -- and that in turn ensures that the GlobalRdrEnv
-       -- has the correct parent for all the names in its range.
-       -- For imported things, we only suck in the binding site later, if ever.
-       -- Reason for all this:
-       --   Suppose module M exports type A.T, and constructor A.MkT
-       --   Then, we know that A.MkT is a subordinate name of A.T,
-       --   even though we aren't at the binding site of A.T
-       --   And it's important, because we may simply re-export A.T
-       --   without ever sucking in the declaration itself.
-
 warnRedundantSourceImport mod_name
   = ptext SLIT("Unnecessary {- SOURCE -} in the import of module")
           <+> quotes (ppr mod_name)
@@ -301,32 +269,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
@@ -345,63 +295,72 @@ 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
-
-       imports = emptyImportAvails {
-                       imp_env = unitModuleEnv this_mod $
-                                 mkNameSet filtered_names
-                   }
-    in
-    returnM (gbl_env, imports)
+             filtered_names 
+               | implicit_prelude = names
+               | otherwise        = filter (not . isBuiltInSyntax) names ;
+
+           ; this_mod = tcg_mod gbl_env
+           ; imports = emptyImportAvails {
+                         imp_env = unitModuleEnv this_mod $
+                                   mkNameSet filtered_names
+                       }
+           }
+
+       ; rdr_env' <- extendRdrEnvRn (tcg_rdr_env gbl_env) names
+
+       ; returnM (gbl_env { tcg_rdr_env = rdr_env',
+                            tcg_imports = imports `plusImportAvails` tcg_imports gbl_env }) 
+       }
+
+extendRdrEnvRn :: 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 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 = LocalDef}
 \end{code}
 
-
-%*********************************************************
-%*                                                     *
-\subsection{Getting binders out of a declaration}
-%*                                                     *
-%*********************************************************
-
 @getLocalDeclBinders@ returns the names for an @HsDecl@.  It's
 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 = ValBindsIn val_decls val_sigs, 
+                                     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 ->
+       --  *signatures*, and there should be no foreign binders 
 
-    returnM (tc_avails ++ map Avail names)
-  where
     new_simple rdr_name = newTopSrcBinder mod Nothing rdr_name
 
-    sig_hs_bndrs = [nm | HsBindGroup _ lsigs _  <- val_decls, 
-                        L _ (Sig nm _) <- lsigs]
-    val_hs_bndrs = collectGroupBinders val_decls
+    sig_hs_bndrs = [nm | L _ (TypeSig nm _) <- val_sigs]
+    val_hs_bndrs = collectHsBindLocatedBinders 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}
@@ -418,7 +377,7 @@ available, and filters it through the import spec (if any).
 
 \begin{code}
 filterImports :: ModIface
-             -> ImportSpec                     -- The span for the entire import decl
+             -> ImpDeclSpec                    -- The span for the entire import decl
              -> Maybe (Bool, [Located (IE RdrName)])   -- Import spec; True => hiding
              -> NameSet                        -- What's available
              -> RnM (NameSet,                  -- What's imported (qualified or unqualified)
@@ -427,14 +386,16 @@ filterImports :: ModIface
        -- Complains if import spec mentions things that the module doesn't export
         -- Warns/informs if import spec contains duplicates.
                        
-mkGenericRdrEnv imp_spec names
-  = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] False }
+mkGenericRdrEnv decl_spec names
+  = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] }
                   | name <- nameSetToList names ]
+  where
+    imp_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }
 
-filterImports iface imp_spec Nothing all_names
-  = returnM (all_names, mkGenericRdrEnv imp_spec all_names)
+filterImports iface decl_spec Nothing all_names
+  = returnM (all_names, mkGenericRdrEnv decl_spec all_names)
 
-filterImports iface imp_spec (Just (want_hiding, import_items)) all_names
+filterImports iface decl_spec (Just (want_hiding, import_items)) all_names
   = mappM (addLocM get_item) import_items      `thenM` \ gres_s ->
     let
        gres = concat gres_s
@@ -447,7 +408,7 @@ filterImports iface imp_spec (Just (want_hiding, import_items)) all_names
        keep n = not (n `elemNameSet` specified_names)
        pruned_avails = filterNameSet keep all_names
     in
-    return (pruned_avails, mkGenericRdrEnv imp_spec pruned_avails)
+    return (pruned_avails, mkGenericRdrEnv decl_spec pruned_avails)
 
   where
     occ_env :: OccEnv Name     -- Maps OccName to corresponding Name
@@ -459,7 +420,7 @@ filterImports iface imp_spec (Just (want_hiding, import_items)) all_names
     sub_env :: NameEnv [Name]
     sub_env = mkSubNameEnv all_names
 
-    bale_out item = addErr (badImportItemErr iface imp_spec item)  `thenM_`
+    bale_out item = addErr (badImportItemErr iface decl_spec item)  `thenM_`
                    returnM []
 
     succeed_with :: Bool -> [Name] -> RnM [GlobalRdrElt]
@@ -468,9 +429,11 @@ 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  = ImpSpec { is_decl = decl_spec, is_item = item_spec }
+           item_spec = ImpSome { is_explicit = explicit, is_iloc = loc }
+           explicit  = all_explicit || isNothing (nameParent_maybe name)
 
     get_item :: IE RdrName -> RnM [GlobalRdrElt]
        -- Empty result for a bad item.
@@ -495,7 +458,7 @@ filterImports iface imp_spec (Just (want_hiding, import_items)) all_names
     get_item item@(IEThingAbs n)
       | want_hiding    -- hiding( C ) 
                        -- Here the 'C' can be a data constructor 
-                       -- *or* a type/class, or even both
+                       --  *or* a type/class, or even both
       = case concat [check_item item, check_item (IEVar data_n)] of
          []    -> bale_out item
          names -> succeed_with True names
@@ -535,7 +498,7 @@ it re-exports @GHC@, which includes @takeMVar#@, whose type includes
 
 \begin{code}
 type ExportAccum       -- The type of the accumulating parameter of
-                       -- the main worker function in exportsFromAvail
+                       -- the main worker function in rnExports
      = ([Module],              -- 'module M's seen so far
        ExportOccMap,           -- Tracks exported occurrence names
        NameSet)                -- The accumulated exported stuff
@@ -548,14 +511,14 @@ type ExportOccMap = OccEnv (Name, IE RdrName)
        --   that have the same occurrence name
 
 
-exportsFromAvail :: Bool  -- False => no 'module M(..) where' header at all
-                -> Maybe [Located (IE RdrName)] -- Nothing => no explicit export list
-                -> RnM NameSet
+rnExports :: Bool  -- False => no 'module M(..) where' header at all
+         -> Maybe [Located (IE RdrName)] -- Nothing => no explicit export list
+         -> RnM NameSet
        -- Complains if two distinct exports have same OccName
         -- Warns about identical exports.
        -- Complains about exports items not in scope
 
-exportsFromAvail explicit_mod exports
+rnExports explicit_mod exports
  = do { TcGblEnv { tcg_rdr_env = rdr_env, 
                   tcg_imports = imports } <- getGblEnv ;
 
@@ -570,6 +533,7 @@ exportsFromAvail explicit_mod exports
                | explicit_mod             = exports
                | ghci_mode == Interactive = Nothing
                | otherwise                = Just [noLoc (IEVar main_RDR_Unqual)] } ;
+               -- ToDo: the 'noLoc' here is unhelpful if 'main' turns out to be out of scope
        exports_from_avail real_exports rdr_env imports }
 
 
@@ -641,6 +605,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` []
@@ -707,23 +672,26 @@ reportDeprecations :: TcGblEnv -> RnM ()
 reportDeprecations tcg_env
   = ifOptM Opt_WarnDeprecations        $
     do { (eps,hpt) <- getEpsAndHpt
+               -- By this time, typechecking is complete, 
+               -- so the PIT is fully populated
        ; mapM_ (check hpt (eps_PIT eps)) all_gres }
   where
-    used_names = findUses (tcg_dus tcg_env) emptyNameSet
+    used_names = allUses (tcg_dus tcg_env) 
+       -- Report on all deprecated uses; hence allUses
     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) $
+      = setSrcSpan (importSpecLoc imp_spec) $
        addWarn (sep [ptext SLIT("Deprecated use of") <+> 
-                       occNameFlavour (nameOccName name) <+> 
+                       pprNonVarNameSpace (occNameSpace (nameOccName name)) <+> 
                        quotes (ppr name),
-                     (parens imp_msg),
+                     (parens imp_msg) <> colon,
                      (ppr deprec_txt) ])
        where
          name_mod = nameModule name
-         imp_mod  = is_mod imp_spec
+         imp_mod  = importSpecModule imp_spec
          imp_msg  = ptext SLIT("imported from") <+> ppr imp_mod <> extra
          extra | imp_mod == name_mod = empty
                | otherwise = ptext SLIT(", but defined in") <+> ppr name_mod
@@ -762,16 +730,21 @@ gre_is_used used_names gre = gre_name gre `elemNameSet` used_names
 %*********************************************************
 
 \begin{code}
-reportUnusedNames :: TcGblEnv -> RnM ()
-reportUnusedNames gbl_env 
-  = do { warnUnusedTopBinds   unused_locals
+reportUnusedNames :: Maybe [Located (IE RdrName)]      -- Export list
+                 -> TcGblEnv -> RnM ()
+reportUnusedNames export_decls gbl_env 
+  = do { traceRn ((text "RUN") <+> (ppr (tcg_dus gbl_env)))
+       ; 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
     used_names = findUses (tcg_dus gbl_env) emptyNameSet
+       -- NB: currently, if f x = g, we only treat 'g' as used if 'f' is used
+       -- Hence findUses
+
     all_used_names = used_names `unionNameSets` 
                     mkNameSet (mapCatMaybes nameParent_maybe (nameSetToList used_names))
                        -- A use of C implies a use of T,
@@ -788,11 +761,6 @@ reportUnusedNames 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 
@@ -804,8 +772,9 @@ reportUnusedNames gbl_env
     
     unused_imports :: [GlobalRdrElt]
     unused_imports = filter unused_imp defined_but_not_used
-    unused_imp (GRE {gre_prov = Imported imp_specs True}) 
-       = not (all (module_unused . is_mod) imp_specs)
+    unused_imp (GRE {gre_prov = Imported imp_specs}) 
+       = not (all (module_unused . importSpecModule) imp_specs)
+         && or [exp | ImpSpec { is_item = ImpSome { is_explicit = exp } } <- imp_specs]
                -- Don't complain about unused imports if we've already said the
                -- entire import is unused
     unused_imp other = False
@@ -813,8 +782,10 @@ reportUnusedNames gbl_env
     -- To figure out the minimal set of imports, start with the things
     -- that are in scope (i.e. in gbl_env).  Then just combine them
     -- into a bunch of avails, so they are properly grouped
+    --
+    -- BUG WARNING: this does not deal properly with qualified imports!
     minimal_imports :: FiniteMap Module AvailEnv
-    minimal_imports0 = emptyFM
+    minimal_imports0 = foldr add_expall   emptyFM         expall_mods
     minimal_imports1 = foldr add_name     minimal_imports0 defined_and_used
     minimal_imports  = foldr add_inst_mod minimal_imports1 direct_import_mods
        -- The last line makes sure that we retain all direct imports
@@ -835,12 +806,33 @@ reportUnusedNames 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 
-       = addToFM_C plusAvailEnv acc (is_mod (head imp_specs))
+    add_name (GRE {gre_name = n, gre_prov = Imported imp_specs}) acc 
+       = addToFM_C plusAvailEnv acc (importSpecModule (head imp_specs))
                    (unitAvailEnv (mk_avail n (nameParent_maybe n)))
     add_name other acc 
        = acc
 
+       -- Modules mentioned as 'module M' in the export list
+    expall_mods = case export_decls of
+                   Nothing -> []
+                   Just es -> [m | L _ (IEModuleContents m) <- es]
+
+       -- This is really bogus.  The idea is that if we see 'module M' in 
+       -- the export list we must retain the import decls that drive it
+       -- If we aren't careful we might see
+       --      module A( module M ) where
+       --        import M
+       --        import N
+       -- and suppose that N exports everything that M does.  Then we 
+       -- must not drop the import of M even though N brings it all into
+       -- scope.
+       --
+       -- BUG WARNING: 'module M' exports aside, what if M.x is mentioned?!
+       --
+       -- The reason that add_expall is bogus is that it doesn't take
+       -- qualified imports into account.  But it's an improvement.
+    add_expall mod acc = addToFM_C plusAvailEnv acc mod emptyAvailEnv
+
        -- n is the name of the thing, p is the name of its parent
     mk_avail n (Just p)                                 = AvailTC p [p,n]
     mk_avail n Nothing | isTcOcc (nameOccName n) = AvailTC n [n]
@@ -855,7 +847,7 @@ reportUnusedNames gbl_env
    
     imports = tcg_imports gbl_env
 
-    direct_import_mods :: [(Module, Maybe Bool, SrcSpan)]
+    direct_import_mods :: [(Module, Bool, SrcSpan)]
        -- See the type of the imp_mods for this triple
     direct_import_mods = moduleEnvElts (imp_mods imports)
 
@@ -863,11 +855,14 @@ reportUnusedNames gbl_env
     -- that are not mentioned in minimal_imports1
     -- [Note: not 'minimal_imports', because that includes directly-imported
     --       modules even if we use nothing from them; see notes above]
-    unused_imp_mods = [(mod,loc) | (mod,imp,loc) <- direct_import_mods,
+    --
+    -- BUG WARNING: does not deal correctly with multiple imports of the same module
+    --             becuase direct_import_mods has only one entry per module
+    unused_imp_mods = [(mod,loc) | (mod,no_imp,loc) <- direct_import_mods,
                       not (mod `elemFM` minimal_imports1),
                       mod /= pRELUDE,
-                      imp /= Just False]
-       -- The Just False part is not to complain about
+                      not no_imp]
+       -- The not no_imp part is not to complain about
        -- import M (), which is an idiom for importing
        -- instance declarations
     
@@ -876,13 +871,80 @@ reportUnusedNames 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 (importSpecLoc 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_decl = ppr (is_as red_decl) <> dot <> ppr occ
+                 | otherwise       = ppr occ
+         occ = nameOccName name
+         red_decl = is_decl red_imp
+    
+    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 whether red_imp could be dropped 
+       --
+       -- NOTE: currently the test does not warn about
+       --              import M( x )
+       --              imoprt N( x )
+       -- even if the same underlying 'x' is involved, because dropping
+       -- either import would change the qualified names in scope (M.x, N.x)
+       -- But if the qualified names aren't used, the import is indeed redundant
+       -- Sadly we don't know that.  Oh well.
+    covers red_imp@(ImpSpec { is_decl = red_decl, is_item = red_item }) 
+          cov_imp@(ImpSpec { is_decl = cov_decl, is_item = cov_item })
+       | red_loc == cov_loc
+       = False         -- Ignore diagonal elements
+       | not (is_as red_decl == is_as cov_decl)
+       = False         -- They bring into scope different qualified names
+       | not (is_qual red_decl) && is_qual cov_decl
+       = False         -- Covering one doesn't bring unqualified name into scope
+       | red_selective
+       = not cov_selective     -- Redundant one is selective and covering one isn't
+         || red_later          -- Both are explicit; tie-break using red_later
+       | otherwise             
+       = not cov_selective     -- Neither import is selective
+         && (is_mod red_decl == is_mod cov_decl)       -- They import the same module
+         && red_later          -- Tie-break
+       where
+         red_loc   = importSpecLoc red_imp
+         cov_loc   = importSpecLoc cov_imp
+         red_later = red_loc > cov_loc
+         cov_selective = selectiveImpItem cov_item
+         red_selective = selectiveImpItem red_item
+
+selectiveImpItem :: ImpItemSpec -> Bool
+selectiveImpItem ImpAll       = False
+selectiveImpItem (ImpSome {}) = True
 
 -- ToDo: deal with original imports with 'qualified' and 'as M' clauses
 printMinimalImports :: FiniteMap Module AvailEnv       -- Minimal imports
@@ -898,7 +960,7 @@ printMinimalImports imps
                                 (vcat (map ppr_mod_ie mod_ies)) })
    }
   where
-    mkFilename this_mod = moduleUserString this_mod ++ ".imports"
+    mkFilename this_mod = moduleString this_mod ++ ".imports"
     ppr_mod_ie (mod_name, ies) 
        | mod_name == pRELUDE 
        = empty
@@ -942,8 +1004,8 @@ printMinimalImports imps
 %************************************************************************
 
 \begin{code}
-badImportItemErr iface imp_spec ie
-  = sep [ptext SLIT("Module"), quotes (ppr (is_mod imp_spec)), source_import,
+badImportItemErr iface decl_spec ie
+  = sep [ptext SLIT("Module"), quotes (ppr (is_mod decl_spec)), source_import,
         ptext SLIT("does not export"), quotes (ppr ie)]
   where
     source_import | mi_boot iface = ptext SLIT("(hi-boot interface)")
@@ -979,16 +1041,16 @@ 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 name_a name_b
+  = 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
+    (name1,name2) | nameSrcLoc name_a > nameSrcLoc name_b = (name_b,name_a)
+                 | otherwise                             = (name_a,name_b)
+       -- Report the error at the later location
 
 dupExportWarn occ_name ie1 ie2
   = hsep [quotes (ppr occ_name),