Remove some unused bindings frm RnNames.
[ghc-hetmet.git] / ghc / compiler / rename / RnNames.lhs
index 5b426fe..a3db173 100644 (file)
@@ -5,55 +5,57 @@
 
 \begin{code}
 module RnNames (
-       rnImports, importsFromLocalDecls, 
-       reportUnusedNames, reportDeprecations, 
-       mkModDeps, exportsToAvails, exportsFromAvail
+       rnImports, mkRdrEnvAndImports, importsFromLocalDecls,
+       rnExports, mkExportNameSet,
+       getLocalDeclBinders, extendRdrEnvRn,
+       reportUnusedNames, reportDeprecations
     ) where
 
 #include "HsVersions.h"
 
-import CmdLineOpts     ( DynFlag(..) )
+import DynFlags                ( DynFlag(..), GhcMode(..) )
 import HsSyn           ( IE(..), ieName, ImportDecl(..), LImportDecl,
-                         ForeignDecl(..), HsGroup(..),
-                         collectGroupBinders, tyClDeclNames 
-                       )
+                         ForeignDecl(..), HsGroup(..), HsValBinds(..),
+                         Sig(..), collectHsBindLocatedBinders, tyClDeclNames,
+                         LIE )
 import RnEnv
-import IfaceEnv                ( lookupOrig, newGlobalBinder )
+import IfaceEnv                ( ifaceExportNames )
 import LoadIface       ( loadSrcInterface )
-import TcRnMonad
+import TcRnMonad hiding (LIE)
 
 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(..),
-                         IfacePackage(..)
+                         lookupIface, ExternalPackageState(..)
                        )
+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}
@@ -67,52 +69,36 @@ import IO           ( openFile, IOMode(..) )
 %************************************************************************
 
 \begin{code}
-rnImports :: [LImportDecl RdrName]
-         -> RnM (GlobalRdrEnv, ImportAvails)
-
+rnImports :: [LImportDecl RdrName] -> RnM [LImportDecl Name]
 rnImports imports
-  = do {       -- PROCESS IMPORT DECLS
-               -- Do the non {- SOURCE -} ones first, so that we get a helpful
-               -- warning for {- SOURCE -} ones that are unnecessary
-         this_mod <- getModule
-       ; implicit_prelude <- doptM Opt_ImplicitPrelude
-       ; let
-           all_imports        = mk_prel_imports this_mod implicit_prelude ++ imports
-           (source, ordinary) = partition is_source_import all_imports
-           is_source_import (L _ (ImportDecl _ is_boot _ _ _)) = is_boot
-
-           get_imports = importsFromImportDecl this_mod
-
-       ; stuff1 <- mappM get_imports ordinary
-       ; stuff2 <- mappM get_imports source
-
-               -- COMBINE RESULTS
-       ; let
-           (imp_gbl_envs, imp_avails) = unzip (stuff1 ++ stuff2)
-           gbl_env :: GlobalRdrEnv
-           gbl_env = foldr plusGlobalRdrEnv emptyGlobalRdrEnv imp_gbl_envs
-
-           all_avails :: ImportAvails
-           all_avails = foldr plusImportAvails emptyImportAvails imp_avails
-
-               -- ALL DONE
-       ; return (gbl_env, all_avails) }
-  where
-       -- NB: opt_NoImplicitPrelude is slightly different to import Prelude ();
-       -- because the former doesn't even look at Prelude.hi for instance 
-       -- declarations, whereas the latter does.
-    mk_prel_imports this_mod implicit_prelude
-       |  this_mod == pRELUDE
-       || explicit_prelude_import
-       || not implicit_prelude
-       = []
-
-       | otherwise = [preludeImportDecl]
-
-    explicit_prelude_import
-      = notNull [ () | L _ (ImportDecl mod _ _ _ _) <- imports, 
-                      unLoc mod == pRELUDE ]
-
+         -- PROCESS IMPORT DECLS
+         -- Do the non {- SOURCE -} ones first, so that we get a helpful
+         -- warning for {- SOURCE -} ones that are unnecessary
+    = do this_mod <- getModule
+         implicit_prelude <- doptM Opt_ImplicitPrelude
+         let all_imports              = mk_prel_imports this_mod implicit_prelude ++ imports
+             (source, ordinary) = partition is_source_import all_imports
+             is_source_import (L _ (ImportDecl _ is_boot _ _ _)) = is_boot
+             get_imports = importsFromImportDeclDirect this_mod
+
+         stuff1 <- mapM get_imports ordinary
+         stuff2 <- mapM get_imports source
+         return (stuff1 ++ stuff2)
+    where
+-- NB: opt_NoImplicitPrelude is slightly different to import Prelude ();
+-- because the former doesn't even look at Prelude.hi for instance 
+-- declarations, whereas the latter does.
+   mk_prel_imports this_mod implicit_prelude
+       |  this_mod == pRELUDE
+          || explicit_prelude_import
+          || not implicit_prelude
+           = []
+       | otherwise = [preludeImportDecl]
+   explicit_prelude_import
+       = notNull [ () | L _ (ImportDecl mod _ _ _ _) <- imports, 
+                  unLoc mod == pRELUDE ]
+
+preludeImportDecl :: LImportDecl RdrName
 preludeImportDecl
   = L loc $
        ImportDecl (L loc pRELUDE)
@@ -121,12 +107,148 @@ preludeImportDecl
               Nothing  {- No "as" -}
               Nothing  {- No import list -}
   where
-    loc = mkGeneralSrcSpan FSLIT("Implicit import declaration")
+    loc = mkGeneralSrcSpan FSLIT("Implicit import declaration")         
+
+mkRdrEnvAndImports :: [LImportDecl Name] -> RnM (GlobalRdrEnv, ImportAvails)
+mkRdrEnvAndImports imports
+  = do this_mod <- getModule
+       let get_imports = importsFromImportDecl this_mod
+       stuff <- mapM get_imports imports
+       let (imp_gbl_envs, imp_avails) = unzip stuff
+           gbl_env :: GlobalRdrEnv
+           gbl_env = foldr plusGlobalRdrEnv emptyGlobalRdrEnv imp_gbl_envs
+
+           all_avails :: ImportAvails
+           all_avails = foldr plusImportAvails emptyImportAvails imp_avails
+       -- ALL DONE
+       return (gbl_env, all_avails)
+
 \end{code}
        
 \begin{code}
+rnImportDecl :: ModIface -> ImpDeclSpec -> ImportDecl RdrName -> NameSet -> RnM (ImportDecl Name)
+rnImportDecl iface decl_spec (ImportDecl loc_imp_mod_name want_boot qual_only as_mod Nothing) all_names
+    = return $ ImportDecl loc_imp_mod_name want_boot qual_only as_mod Nothing
+rnImportDecl iface decl_spec (ImportDecl loc_imp_mod_name want_boot qual_only as_mod (Just (want_hiding,import_items))) all_names
+    = do import_items_mbs <- mapM (srcSpanWrapper) import_items
+         let rn_import_items = concat . catMaybes $ import_items_mbs
+         return $ ImportDecl loc_imp_mod_name want_boot qual_only as_mod (Just (want_hiding,rn_import_items))
+    where
+    srcSpanWrapper (L span ieRdr)
+        = setSrcSpan span $
+          case get_item ieRdr of
+            Nothing
+                -> do addErr (badImportItemErr iface decl_spec ieRdr)
+                      return Nothing
+            Just ieNames
+                -> return (Just [L span ie | ie <- ieNames])
+    occ_env :: OccEnv Name     -- Maps OccName to corresponding Name
+    occ_env = mkOccEnv [(nameOccName n, n) | n <- nameSetToList all_names]
+       -- This env will have entries for data constructors too,
+       -- they won't make any difference because naked entities like T
+       -- in an import list map to TcOccs, not VarOccs.
+
+    sub_env :: NameEnv [Name]
+    sub_env = mkSubNameEnv all_names
+
+    get_item :: IE RdrName -> Maybe [IE Name]
+        -- Empty result for a bad item.
+       -- Singleton result is typical case.
+        -- Can have two when we are hiding, and mention C which might be
+       --      both a class and a data constructor.  
+    get_item item@(IEModuleContents _) 
+      = Nothing
+
+    get_item (IEThingAll tc)
+      = do name <- check_name tc
+           return [IEThingAll name]
+{-
+   -> -- This occurs when you import T(..), but
+                       -- only export T abstractly.  The single [n]
+                       -- in the AvailTC is the type or class itself
+                       ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn tc)) `thenM_`
+                       return [ IEThingAll n ]
+
+         names -> return [ IEThingAll n | n <- names ]
+-}
+
+    get_item (IEThingAbs tc)
+        | want_hiding   -- hiding ( C )
+                        -- Here the 'C' can be a data constructor 
+                        --  *or* a type/class, or even both
+            = case catMaybes [check_name tc, check_name (setRdrNameSpace tc srcDataName)] of
+                []    -> Nothing
+                names -> return [ IEThingAbs n | n <- names ]
+        | otherwise
+            = do name <- check_name tc
+                 return [IEThingAbs name]
+    get_item (IEThingWith n ns) -- import (C (A,B))
+        = do name <- check_name n
+             let env = mkOccEnv [(nameOccName s, s) | s <- subNames sub_env name]
+                 mb_names = map (lookupOccEnv env . rdrNameOcc) ns
+             names <- sequence mb_names
+             return [IEThingWith name names]
+
+    get_item (IEVar n)
+      = do name <- check_name n
+           return [IEVar name]
+
+    check_name :: RdrName -> Maybe Name
+    check_name rdrName
+       = lookupOccEnv occ_env (rdrNameOcc rdrName)
+
+
+importsFromImportDeclDirect :: Module
+                            -> LImportDecl RdrName
+                            -> RnM (LImportDecl Name)
+importsFromImportDeclDirect this_mod
+                            (L loc importDecl@(ImportDecl loc_imp_mod_name want_boot qual_only as_mod imp_details))
+    = setSrcSpan loc $
+      do iface <- loadSrcInterface doc imp_mod_name want_boot
+         -- Compiler sanity check: if the import didn't say
+         -- {-# SOURCE #-} we should not get a hi-boot file
+         WARN( not want_boot && mi_boot iface, ppr imp_mod_name ) $ do
+         -- Issue a user warning for a redundant {- SOURCE -} import
+         -- NB that we arrange to read all the ordinary imports before 
+         -- any of the {- SOURCE -} imports
+         warnIf (want_boot && not (mi_boot iface))
+                    (warnRedundantSourceImport imp_mod_name)
+
+         let filtered_exports = filter not_this_mod (mi_exports iface)
+             not_this_mod (mod,_) = mod /= this_mod
+
+       -- If the module exports anything defined in this module, just ignore it.
+       -- Reason: otherwise it looks as if there are two local definition sites
+       -- for the thing, and an error gets reported.  Easiest thing is just to
+       -- filter them out up front. This situation only arises if a module
+       -- imports itself, or another module that imported it.  (Necessarily,
+       -- this invoves a loop.)  
+       --
+       -- Tiresome consequence: if you say
+       --      module A where
+       --         import B( AType )
+       --         type AType = ...
+       --
+       --      module B( AType ) where
+       --         import {-# SOURCE #-} A( AType )
+       --
+       -- then you'll get a 'B does not export AType' message.  Oh well.
+
+             qual_mod_name = case as_mod of
+                               Nothing             -> imp_mod_name
+                               Just another_name -> another_name
+             imp_spec  = ImpDeclSpec { is_mod = imp_mod_name, is_qual = qual_only,  
+                                       is_dloc = loc, is_as = qual_mod_name }
+
+        -- Get the total imports, and filter them according to the import list
+         total_avails <- ifaceExportNames filtered_exports
+         importDecl' <- rnImportDecl iface imp_spec importDecl total_avails
+         return (L loc importDecl')
+    where imp_mod_name = unLoc loc_imp_mod_name
+          doc = ppr imp_mod_name <+> ptext SLIT("is directly imported")
+
 importsFromImportDecl :: Module
-                     -> LImportDecl RdrName
+                     -> LImportDecl Name
                      -> RnM (GlobalRdrEnv, ImportAvails)
 
 importsFromImportDecl this_mod
@@ -180,11 +302,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) ->
 
@@ -199,7 +321,7 @@ importsFromImportDecl this_mod
 
        (dependent_mods, dependent_pkgs) 
           = case mi_package iface of
-               ThisPackage ->
+               HomePackage ->
                -- Imported module is from the home package
                -- Take its dependent modules and add imp_mod itself
                -- Take its dependent packages unchanged
@@ -213,18 +335,17 @@ importsFromImportDecl this_mod
                -- check.  See LoadIface.loadHiBootInterface
                  ((imp_mod_name, want_boot) : dep_mods deps, dep_pkgs deps)
 
-               ExternalPackage pkg ->
+               ExtPackage pkg ->
                -- Imported module is from another package
                -- Dump the dependent modules
                -- Add the package imp_mod comes from to the dependent packages
                 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 +368,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 +388,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,54 +414,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 ->
-    mappM new_simple (for_hs_bndrs ++ val_hs_bndrs)    `thenM` \ simple_avails ->
-    returnM (tc_avails ++ simple_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
-    new_simple rdr_name = newTopSrcBinder mod Nothing rdr_name `thenM` \ name ->
-                         returnM (Avail name)
+    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 
 
-    val_hs_bndrs = collectGroupBinders val_decls
+    new_simple rdr_name = newTopSrcBinder mod Nothing rdr_name
+
+    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}
@@ -409,8 +496,8 @@ available, and filters it through the import spec (if any).
 
 \begin{code}
 filterImports :: ModIface
-             -> ImportSpec                     -- The span for the entire import decl
-             -> Maybe (Bool, [Located (IE RdrName)])   -- Import spec; True => hiding
+             -> ImpDeclSpec                    -- The span for the entire import decl
+             -> Maybe (Bool, [LIE Name])       -- Import spec; True => hiding
              -> NameSet                        -- What's available
              -> RnM (NameSet,                  -- What's imported (qualified or unqualified)
                      GlobalRdrEnv)             -- Same again, but in GRE form
@@ -418,91 +505,63 @@ 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 ]
-
-filterImports iface imp_spec Nothing all_names
-  = returnM (all_names, mkGenericRdrEnv imp_spec all_names)
-
-filterImports iface imp_spec (Just (want_hiding, import_items)) all_names
-  = mappM (addLocM get_item) import_items      `thenM` \ gres_s ->
-    let
-       gres = concat gres_s
-       specified_names = mkNameSet (map gre_name gres)
-    in
-    if not want_hiding then
-      return (specified_names, mkGlobalRdrEnv gres)
-    else
-    let
-       keep n = not (n `elemNameSet` specified_names)
-       pruned_avails = filterNameSet keep all_names
-    in
-    return (pruned_avails, mkGenericRdrEnv imp_spec pruned_avails)
-
   where
-    occ_env :: OccEnv Name     -- Maps OccName to corresponding Name
-    occ_env = mkOccEnv [(nameOccName n, n) | n <- nameSetToList all_names]
-       -- This env will have entries for data constructors too,
-       -- they won't make any difference because naked entities like T
-       -- in an import list map to TcOccs, not VarOccs.
-
-    sub_env :: NameEnv [Name]
+    imp_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }
+
+filterImports iface decl_spec Nothing all_names
+  = return (all_names, mkGenericRdrEnv decl_spec all_names)
+
+filterImports iface decl_spec (Just (want_hiding, import_items)) all_names
+  = mapM (addLocM get_item) import_items >>= \gres_s ->
+    let gres = concat gres_s
+        specified_names = mkNameSet (map gre_name gres)
+    in if not want_hiding then
+       return (specified_names, mkGlobalRdrEnv gres)
+    else let keep n = not (n `elemNameSet` specified_names)
+             pruned_avails = filterNameSet keep all_names
+         in return (pruned_avails, mkGenericRdrEnv decl_spec pruned_avails)
+  where
+    sub_env :: NameEnv [Name]  -- Classify each name by its parent
     sub_env = mkSubNameEnv all_names
 
-    bale_out item = addErr (badImportItemErr iface imp_spec item)  `thenM_`
-                   returnM []
-
     succeed_with :: Bool -> [Name] -> RnM [GlobalRdrElt]
     succeed_with all_explicit names
       = do { loc <- getSrcSpanM
           ; 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]
+    get_item :: IE Name -> RnM [GlobalRdrElt]
        -- Empty result for a bad item.
        -- Singleton result is typical case.
        -- Can have two when we are hiding, and mention C which might be
        --      both a class and a data constructor.  
     get_item item@(IEModuleContents _) 
-      = bale_out item
+        -- This case should be filtered out by 'rnImports'.
+        = panic "filterImports: IEModuleContents?" 
 
-    get_item item@(IEThingAll tc)
-      = case check_item item of
-         []    -> bale_out item
+    get_item (IEThingAll name)
+        = case subNames sub_env name of
+            [] -> do ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn name))
+                     succeed_with False [name]
+            names -> succeed_with False (name:names)
 
-         [n]   -> -- This occurs when you import T(..), but
-                       -- only export T abstractly.  The single [n]
-                       -- in the AvailTC is the type or class itself
-                       ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn tc)) `thenM_`
-                       succeed_with False [n]
+    get_item (IEThingAbs name)
+        = succeed_with True [name]
 
-         names -> succeed_with False names
+    get_item (IEThingWith name names)
+        = succeed_with True (name:names)
+    get_item (IEVar name)
+        = succeed_with True [name]
 
-    get_item item@(IEThingAbs n)
-      | want_hiding    -- hiding( C ) 
-                       -- Here the 'C' can be a data constructor 
-                       -- *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
-      where
-       data_n = setRdrNameSpace n srcDataName
-
-    get_item item
-      = case check_item item of
-         []    -> bale_out item
-         names -> succeed_with True names
-
-    check_item :: IE RdrName -> [Name]
-    check_item item 
-       = case lookupOccEnv occ_env (rdrNameOcc (ieName item)) of
-           Nothing   -> []
-           Just name -> filterAvail item name sub_env
 \end{code}
 
 
@@ -526,29 +585,60 @@ 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
 emptyExportAccum = ([], emptyOccEnv, emptyNameSet) 
 
-type ExportOccMap = OccEnv (Name, IE RdrName)
+type ExportOccMap = OccEnv (Name, IE Name)
        -- Tracks what a particular exported OccName
        --   in an export list refers to, and which item
        --   it came from.  It's illegal to export two distinct things
        --   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 :: Maybe [LIE RdrName]
+          -> RnM (Maybe [LIE Name])
+rnExports Nothing = return Nothing
+rnExports (Just exports)
+    = do TcGblEnv { tcg_imports = ImportAvails { imp_env = imp_env } } <- getGblEnv
+         let sub_env :: NameEnv [Name] -- Classify each name by its parent
+             sub_env = mkSubNameEnv (foldModuleEnv unionNameSets emptyNameSet imp_env)
+             inLoc fn (L span x)
+                 = do x' <- fn x
+                      return (L span x')
+             rnExport (IEVar rdrName)
+                 = do name <- lookupGlobalOccRn rdrName
+                      return (IEVar name)
+             rnExport (IEThingAbs rdrName)
+                 = do name <- lookupGlobalOccRn rdrName
+                      return (IEThingAbs name)
+             rnExport (IEThingAll rdrName)
+                 = do name <- lookupGlobalOccRn rdrName
+                      return (IEThingAll name)
+             rnExport (IEThingWith rdrName rdrNames)
+                 = do name <- lookupGlobalOccRn rdrName
+                      let env = mkOccEnv [(nameOccName s, s) | s <- subNames sub_env name]
+                          mb_names = map (lookupOccEnv env . rdrNameOcc) rdrNames
+                      if any isNothing mb_names
+                         then -- The export error will be reporting in 'mkExportNameSet'
+                              return (IEThingWith name [])
+                         else return (IEThingWith name (catMaybes mb_names))
+             rnExport (IEModuleContents mod)
+                 = return (IEModuleContents mod)
+         rn_exports <- mapM (inLoc rnExport) exports
+         return (Just rn_exports)
+
+mkExportNameSet :: Bool  -- False => no 'module M(..) where' header at all
+                -> Maybe [LIE Name] -- 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
- = do { TcGblEnv { tcg_rdr_env = rdr_env, 
-                  tcg_imports = imports } <- getGblEnv ;
+mkExportNameSet explicit_mod exports
+ = do TcGblEnv { tcg_rdr_env = rdr_env, 
+                 tcg_imports = imports } <- getGblEnv
 
        -- If the module header is omitted altogether, then behave
        -- as if the user had written "module Main(main) where..."
@@ -556,12 +646,17 @@ exportsFromAvail explicit_mod exports
        -- written "module Main where ..."
        -- Reason: don't want to complain about 'main' not in scope
        --         in interactive mode
-       ghci_mode <- getGhciMode ;
-       let { real_exports 
-               | explicit_mod             = exports
-               | ghci_mode == Interactive = Nothing
-               | otherwise                = Just [noLoc (IEVar main_RDR_Unqual)] } ;
-       exports_from_avail real_exports rdr_env imports }
+      ghci_mode <- getGhciMode
+      real_exports <- case () of
+                        () | explicit_mod
+                               -> return exports
+                           | ghci_mode == Interactive
+                               -> return Nothing
+                           | otherwise
+                               -> do mainName <- lookupGlobalOccRn main_RDR_Unqual
+                                     return (Just [noLoc (IEVar mainName)])
+               -- ToDo: the 'noLoc' here is unhelpful if 'main' turns out to be out of scope
+      exports_from_avail real_exports rdr_env imports
 
 
 exports_from_avail Nothing rdr_env imports
@@ -573,16 +668,16 @@ exports_from_avail Nothing rdr_env imports
                       isLocalGRE gre ])
 
 exports_from_avail (Just items) rdr_env (ImportAvails { imp_env = imp_env }) 
-  = foldlM do_litem emptyExportAccum items    `thenM` \ (_, _, exports) ->
-    returnM exports
+  = do (_, _, exports) <- foldlM do_litem emptyExportAccum items
+       return exports
   where
     sub_env :: NameEnv [Name]  -- Classify each name by its parent
     sub_env = mkSubNameEnv (foldModuleEnv unionNameSets emptyNameSet imp_env)
 
-    do_litem :: ExportAccum -> Located (IE RdrName) -> RnM ExportAccum
+    do_litem :: ExportAccum -> LIE Name -> RnM ExportAccum
     do_litem acc = addLocM (exports_from_item acc)
 
-    exports_from_item :: ExportAccum -> IE RdrName -> RnM ExportAccum
+    exports_from_item :: ExportAccum -> IE Name -> RnM ExportAccum
     exports_from_item acc@(mods, occs, exports) ie@(IEModuleContents mod)
        | mod `elem` mods       -- Duplicate export of M
        = do { warn_dup_exports <- doptM Opt_WarnDuplicateExports ;
@@ -591,47 +686,36 @@ exports_from_avail (Just items) rdr_env (ImportAvails { imp_env = imp_env })
 
        | otherwise
        = case lookupModuleEnv imp_env mod of
-           Nothing -> addErr (modExportErr mod)        `thenM_`
-                      returnM acc
-           Just names
-               -> let
-                    new_exports = filterNameSet (inScopeUnqual rdr_env) names
-                  in
-
-               -- This check_occs not only finds conflicts between this item
-               -- and others, but also internally within this item.  That is,
-               -- if 'M.x' is in scope in several ways, we'll have several
-               -- members of mod_avails with the same OccName.
-                  check_occs ie occs (nameSetToList new_exports)       `thenM` \ occs' ->
-                  returnM (mod:mods, occs', exports `unionNameSets` new_exports)
+            Nothing -> do addErr (modExportErr mod)
+                          return acc
+            Just names
+                -> do let new_exports = filterNameSet (inScopeUnqual rdr_env) names
+                      -- This check_occs not only finds conflicts between this item
+                      -- and others, but also internally within this item.  That is,
+                      -- if 'M.x' is in scope in several ways, we'll have several
+                      -- members of mod_avails with the same OccName.
+                      occs' <- check_occs ie occs (nameSetToList new_exports)
+                      return (mod:mods, occs', exports `unionNameSets` new_exports)
 
     exports_from_item acc@(mods, occs, exports) ie
-       = lookupGlobalOccRn (ieName ie)                 `thenM` \ name -> 
-         if isUnboundName name then
-               returnM acc     -- Avoid error cascade
-         else let
-           new_exports = filterAvail ie name sub_env
-         in
-         checkErr (not (null new_exports)) (exportItemErr ie)  `thenM_`
-         checkForDodgyExport ie new_exports                    `thenM_`
-          check_occs ie occs new_exports                       `thenM` \ occs' ->
-         returnM (mods, occs', addListToNameSet exports new_exports)
+        = if isUnboundName (ieName ie)
+          then return acc      -- Avoid error cascade
+          else let new_exports = filterAvail ie sub_env in
+          do checkErr (not (null new_exports)) (exportItemErr ie)
+             checkForDodgyExport ie new_exports
+             occs' <- check_occs ie occs new_exports
+             return (mods, occs', addListToNameSet exports new_exports)
          
 -------------------------------
-filterAvail :: IE RdrName      -- Wanted
-           -> Name             -- The Name of the ieName of the item
+filterAvail :: IE Name         -- Wanted
            -> NameEnv [Name]   -- Maps type/class names to their sub-names
-           -> [Name]           -- Empty if even one thing reqd is missing
-
-filterAvail (IEVar _)           n subs = [n]
-filterAvail (IEThingAbs _)      n subs = [n]
-filterAvail (IEThingAll _)      n subs = n : subNames subs n
-filterAvail (IEThingWith _ rdrs) n subs
-  | any isNothing mb_names = []
-  | otherwise             = n : catMaybes mb_names
-  where
-    env = mkOccEnv [(nameOccName s, s) | s <- subNames subs n]
-    mb_names = map (lookupOccEnv env . rdrNameOcc) rdrs
+           -> [Name]
+
+filterAvail (IEVar n)          subs = [n]
+filterAvail (IEThingAbs n)     subs = [n]
+filterAvail (IEThingAll n)     subs = n : subNames subs n
+filterAvail (IEThingWith n ns) subs = n : ns
+filterAvail (IEModuleContents _) _  = panic "filterAvail"
 
 subNames :: NameEnv [Name] -> Name -> [Name]
 subNames env n = lookupNameEnv env n `orElse` []
@@ -654,7 +738,7 @@ inScopeUnqual :: GlobalRdrEnv -> Name -> Bool
 inScopeUnqual env n = any unQualOK (lookupGRE_Name env n)
 
 -------------------------------
-checkForDodgyExport :: IE RdrName -> [Name] -> RnM ()
+checkForDodgyExport :: IE Name -> [Name] -> RnM ()
 checkForDodgyExport ie@(IEThingAll tc) [n] 
   | isTcOcc (nameOccName n) = addWarn (dodgyExportWarn tc)
        -- This occurs when you export T(..), but
@@ -665,7 +749,7 @@ checkForDodgyExport ie@(IEThingAll tc) [n]
 checkForDodgyExport _ _ = return ()
 
 -------------------------------
-check_occs :: IE RdrName -> ExportOccMap -> [Name] -> RnM ExportOccMap
+check_occs :: IE Name -> ExportOccMap -> [Name] -> RnM ExportOccMap
 check_occs ie occs names
   = foldlM check occs names
   where
@@ -698,23 +782,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
@@ -753,16 +840,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 [LIE 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,
@@ -779,11 +871,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 
@@ -795,8 +882,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
@@ -804,8 +892,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
@@ -826,12 +916,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]
@@ -846,7 +957,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)
 
@@ -854,11 +965,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
     
@@ -867,13 +981,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
@@ -889,7 +1070,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
@@ -899,8 +1080,8 @@ printMinimalImports imps
        = ptext SLIT("import") <+> ppr mod_name <> 
                    parens (fsep (punctuate comma (map ppr ies)))
 
-    to_ies (mod, avail_env) = mappM to_ie (availEnvElts avail_env)     `thenM` \ ies ->
-                             returnM (mod, ies)
+    to_ies (mod, avail_env) = do ies <- mapM to_ie (availEnvElts avail_env)
+                                 returnM (mod, ies)
 
     to_ie :: AvailInfo -> RnM (IE Name)
        -- The main trick here is that if we're importing all the constructors
@@ -933,8 +1114,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)")
@@ -970,16 +1151,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),