[project @ 2004-10-20 13:34:04 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / RnNames.lhs
index d7eaf76..4dfcc13 100644 (file)
@@ -6,7 +6,8 @@
 \begin{code}
 module RnNames (
        rnImports, importsFromLocalDecls, exportsFromAvail,
-       reportUnusedNames, mkModDeps, exportsToAvails
+       reportUnusedNames, reportDeprecations, 
+       mkModDeps, exportsToAvails
     ) where
 
 #include "HsVersions.h"
@@ -22,22 +23,23 @@ import LoadIface    ( loadSrcInterface )
 import TcRnMonad
 
 import FiniteMap
-import PrelNames       ( pRELUDE_Name, isBuiltInSyntaxName, isUnboundName,
+import PrelNames       ( pRELUDE_Name, isUnboundName,
                          main_RDR_Unqual )
 import Module          ( Module, ModuleName, moduleName, mkPackageModule,
                          moduleNameUserString, isHomeModule,
                          unitModuleEnvByName, unitModuleEnv, 
                          lookupModuleEnvByName, moduleEnvElts )
-import Name            ( Name, nameSrcLoc, nameOccName, nameModuleName,
-                         nameParent, nameParent_maybe, isExternalName )
+import Name            ( Name, nameSrcLoc, nameOccName, nameModuleName, isWiredInName,
+                         nameParent, nameParent_maybe, isExternalName, nameModule,
+                         isBuiltInSyntax )
 import NameSet
-import NameEnv
-import OccName         ( srcDataName, isTcOcc, OccEnv, 
+import OccName         ( srcDataName, isTcOcc, occNameFlavour, OccEnv, 
                          mkOccEnv, lookupOccEnv, emptyOccEnv, extendOccEnv )
 import HscTypes                ( GenAvailInfo(..), AvailInfo, Avails, GhciMode(..),
-                         IfaceExport, 
+                         IfaceExport, HomePackageTable, PackageIfaceTable, 
                          availName, availNames, availsToNameSet, unQualInScope, 
-                         Deprecs(..), ModIface(..), Dependencies(..)
+                         Deprecs(..), ModIface(..), Dependencies(..), lookupIface,
+                         ExternalPackageState(..)
                        )
 import RdrName         ( RdrName, rdrNameOcc, setRdrNameSpace, 
                          GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..), 
@@ -46,12 +48,13 @@ import RdrName              ( RdrName, rdrNameOcc, setRdrNameSpace,
                          Provenance(..), ImportSpec(..), 
                          isLocalGRE, pprNameProvenance )
 import Outputable
-import Maybes          ( isJust, isNothing, catMaybes, mapCatMaybes )
+import Maybes          ( isNothing, catMaybes, mapCatMaybes, seqMaybe )
 import SrcLoc          ( noSrcLoc, Located(..), mkGeneralSrcSpan,
-                         unLoc, noLoc )
+                         unLoc, noLoc, srcLocSpan, combineSrcSpans, SrcSpan )
+import BasicTypes      ( DeprecTxt )
 import ListSetOps      ( removeDups )
-import Util            ( sortLt, notNull, isSingleton )
-import List            ( partition, insert )
+import Util            ( sortLe, notNull, isSingleton )
+import List            ( partition )
 import IO              ( openFile, IOMode(..) )
 \end{code}
 
@@ -68,32 +71,32 @@ rnImports :: [LImportDecl RdrName]
          -> RnM (GlobalRdrEnv, ImportAvails)
 
 rnImports imports
-  =            -- PROCESS IMPORT DECLS
+  = do {       -- PROCESS IMPORT DECLS
                -- Do the non {- SOURCE -} ones first, so that we get a helpful
                -- warning for {- SOURCE -} ones that are unnecessary
-       getModule                               `thenM` \ this_mod ->
-       doptM Opt_NoImplicitPrelude             `thenM` \ opt_no_prelude -> 
-       let
-         all_imports        = mk_prel_imports this_mod opt_no_prelude ++ imports
-         (source, ordinary) = partition is_source_import all_imports
-         is_source_import (L _ (ImportDecl _ is_boot _ _ _)) = is_boot
-
-         get_imports = importsFromImportDecl this_mod
-       in
-       mappM get_imports ordinary      `thenM` \ stuff1 ->
-       mappM get_imports source        `thenM` \ stuff2 ->
+         this_mod <- getModule
+       ; opt_no_prelude <- doptM Opt_NoImplicitPrelude
+       ; let
+           all_imports      = mk_prel_imports this_mod opt_no_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
+       ; 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
-       in
+
                -- ALL DONE
-       returnM (gbl_env, all_avails)
+       ; 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 
@@ -129,7 +132,7 @@ importsFromImportDecl :: Module
 importsFromImportDecl this_mod
        (L loc (ImportDecl loc_imp_mod_name want_boot qual_only as_mod imp_details))
   = 
-    addSrcSpan loc $
+    setSrcSpan loc $
 
        -- If there's an error in loadInterface, (e.g. interface
        -- file not found) we get lots of spurious errors from 'filterImports'
@@ -180,7 +183,6 @@ importsFromImportDecl this_mod
                          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 }
-       mk_deprec = mi_dep_fn iface
     in
 
        -- Get the total imports, and filter them according to the import list
@@ -190,26 +192,29 @@ importsFromImportDecl this_mod
 
     let
        -- Compute new transitive dependencies
-       orphans | is_orph   = insert imp_mod_name (dep_orphs deps)
+
+       orphans | is_orph   = ASSERT( not (imp_mod_name `elem` dep_orphs deps) )
+                             imp_mod_name : dep_orphs deps
                | otherwise = dep_orphs deps
 
        (dependent_mods, dependent_pkgs) 
           | isHomeModule imp_mod 
           =    -- Imported module is from the home package
-               -- Take its dependent modules and
-               --      (a) remove this_mod (might be there as a hi-boot)
-               --      (b) add imp_mod itself
+               -- Take its dependent modules and add imp_mod itself
                -- Take its dependent packages unchanged
-            ((imp_mod_name, want_boot) : filter not_self (dep_mods deps), dep_pkgs deps)
+               -- NB: (dep_mods deps) might include a hi-boot file for the module being
+               --      compiled, CM. Do *not* filter this out (as we used to), because when 
+               --      we've finished dealing with the direct imports we want to know if any 
+               --      of them depended on CM.hi-boot, in which case we should do the hi-boot
+               --      consistency check.  See LoadIface.loadHiBootInterface
+            ((imp_mod_name, want_boot) : dep_mods deps, dep_pkgs deps)
 
           | otherwise  
           =    -- Imported module is from another package
                -- Dump the dependent modules
                -- Add the package imp_mod comes from to the dependent packages
-               -- from imp_mod
-            ([], insert (mi_package iface) (dep_pkgs deps))
-
-       not_self (m, _) = m /= this_mod_name
+            ASSERT( not (mi_package iface `elem` dep_pkgs deps) )
+            ([], mi_package iface : dep_pkgs deps)
 
        import_all = case imp_details of
                        Just (is_hiding, ls)     -- Imports are spec'd explicitly
@@ -224,7 +229,7 @@ importsFromImportDecl this_mod
        imports   = ImportAvails { 
                        imp_qual     = unitModuleEnvByName qual_mod_name avail_env,
                        imp_env      = avail_env,
-                       imp_mods     = unitModuleEnv imp_mod (imp_mod, import_all),
+                       imp_mods     = unitModuleEnv imp_mod (imp_mod, import_all, loc),
                        imp_orphs    = orphans,
                        imp_dep_mods = mkModDeps dependent_mods,
                        imp_dep_pkgs = dependent_pkgs }
@@ -301,22 +306,15 @@ importsFromLocalDecls group
        -- 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_ (addErr . dupDeclErr) dups                  `thenM_` 
+    mappM_ addDupDeclErr dups                  `thenM_` 
 
     doptM Opt_NoImplicitPrelude                `thenM` \ implicit_prelude ->
     let
        mod_name = moduleName this_mod
        prov     = LocalDef mod_name
        gbl_env  = mkGlobalRdrEnv gres
-       gres     = [ GRE { gre_name = name, gre_prov = prov, gre_deprec = Nothing}
+       gres     = [ GRE { gre_name = name, gre_prov = prov}
                   | name <- all_names]
-           -- gre_deprecs = Nothing: don't deprecate locally defined names
-           -- For a start, we may be exporting a deprecated thing
-           -- Also we may use a deprecated thing in the defn of another
-           -- deprecated things.  We may even use a deprecated thing in
-           -- the defn of a non-deprecated thing, when changing a module's 
-           -- interface
-
 
            -- Optimisation: filter out names for built-in syntax
            -- They just clutter up the environment (esp tuples), and the parser
@@ -339,10 +337,10 @@ importsFromLocalDecls group
 
        avails' | implicit_prelude = filter not_built_in_syntax avails
                | otherwise        = avails
-       not_built_in_syntax a = not (all isBuiltInSyntaxName (availNames a))
+       not_built_in_syntax a = not (all isBuiltInSyntax (availNames a))
                -- Only filter it if all the names of the avail are built-in
                -- In particular, lists have (:) which is not built in syntax
-               -- so we don't filter it out.  [Sept 03: wrong: see isBuiltInSyntaxName]
+               -- so we don't filter it out.  [Sept 03: wrong: see isBuiltInSyntax]
 
        avail_env = mkAvailEnv avails'
        imports   = emptyImportAvails {
@@ -408,34 +406,37 @@ filterImports :: ModIface
              -> ImportSpec                     -- The span for the entire import decl
              -> Maybe (Bool, [Located (IE RdrName)])   -- Import spec; True => hiding
              -> [AvailInfo]                    -- What's available
-             -> RnM (AvailEnv,                 -- What's imported
-                     GlobalRdrEnv)             -- ...in two forms
+             -> RnM (AvailEnv,                 -- What's imported (qualified or unqualified)
+                     GlobalRdrEnv)             -- Same again, but in GRE form
 
        -- Complains if import spec mentions things that the module doesn't export
         -- Warns/informs if import spec contains duplicates.
-mkGenericRdrEnv iface imp_spec avails
-  = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] False,
-                          gre_deprec = mi_dep_fn iface name }
-                  | avail <- avails, name <- availNames avail ]
                        
+mkGenericRdrEnv imp_spec avails
+  = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] False }
+                  | avail <- avails, name <- availNames avail ]
+
 filterImports iface imp_spec Nothing total_avails
-  = returnM (mkAvailEnv total_avails, mkGenericRdrEnv iface imp_spec total_avails)
+  = returnM (mkAvailEnv total_avails, 
+            mkGenericRdrEnv imp_spec total_avails)
 
 filterImports iface imp_spec (Just (want_hiding, import_items)) total_avails
-  = mapAndUnzipM (addLocM get_item) import_items       `thenM` \ (avails, gres) ->
+  = mapAndUnzipM (addLocM get_item) import_items       `thenM` \ (avails_s, gres) ->
     let
-       all_avails = foldr plusAvailEnv     emptyAvailEnv     avails
-       rdr_env    = foldr plusGlobalRdrEnv emptyGlobalRdrEnv gres
+       avails = concat avails_s
     in
     if not want_hiding then
-       returnM (all_avails, rdr_env)
+      return (mkAvailEnv avails,
+             foldr plusGlobalRdrEnv emptyGlobalRdrEnv gres)
     else
-    let        -- Hide stuff in all_avails
-          hidden = availsToNameSet (availEnvElts all_avails)
-          keep n = not (n `elemNameSet` hidden)
-          pruned_avails = pruneAvails keep total_avails
-    in
-    returnM (mkAvailEnv pruned_avails, mkGenericRdrEnv iface imp_spec pruned_avails)
+      let
+       hidden = availsToNameSet avails
+       keep n = not (n `elemNameSet` hidden)
+       pruned_avails = pruneAvails keep total_avails
+      in
+      return (mkAvailEnv pruned_avails,
+             mkGenericRdrEnv imp_spec pruned_avails)
+
   where
     import_fm :: OccEnv AvailInfo
     import_fm = mkOccEnv [ (nameOccName name, avail) 
@@ -446,24 +447,21 @@ filterImports iface imp_spec (Just (want_hiding, import_items)) total_avails
        -- in an import list map to TcOccs, not VarOccs.
 
     bale_out item = addErr (badImportItemErr iface imp_spec item)      `thenM_`
-                   returnM (emptyAvailEnv, emptyGlobalRdrEnv)
-
-    mk_deprec = mi_dep_fn iface
+                   returnM ([], emptyGlobalRdrEnv)
 
-    succeed_with :: Bool -> AvailInfo -> RnM (AvailEnv, GlobalRdrEnv)
+    succeed_with :: Bool -> AvailInfo -> RnM ([AvailInfo], GlobalRdrEnv)
     succeed_with all_explicit avail
       = do { loc <- getSrcSpanM
-          ; returnM (unitAvailEnv avail, 
+          ; returnM ([avail], 
                      mkGlobalRdrEnv (map (mk_gre loc) (availNames avail))) }
       where
        mk_gre loc name = GRE { gre_name = name, 
-                               gre_prov = Imported [this_imp_spec loc] (explicit name), 
-                               gre_deprec = mk_deprec name }
+                               gre_prov = Imported [this_imp_spec loc] (explicit name) }
        this_imp_spec loc = imp_spec { is_loc = loc }
        explicit name = all_explicit || name == main_name
        main_name = availName avail
 
-    get_item :: IE RdrName -> RnM (AvailEnv, GlobalRdrEnv)
+    get_item :: IE RdrName -> RnM ([AvailInfo], GlobalRdrEnv)
        -- Empty result for a bad item.
        -- Singleton result is typical case.
        -- Can have two when we are hiding, and mention C which might be
@@ -477,16 +475,17 @@ filterImports iface imp_spec (Just (want_hiding, import_items)) total_avails
          Just avail@(AvailTC _ [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_WarnMisc (addWarn (dodgyImportWarn tc))      `thenM_`
+                                       ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn tc)) `thenM_`
                                        succeed_with False avail
          Just avail                 -> succeed_with False avail
 
     get_item item@(IEThingAbs n)
       | want_hiding    -- hiding( C ) 
-                       -- Here the 'C' can be a data constructor *or* a type/class
+                       -- Here the 'C' can be a data constructor 
+                       -- *or* a type/class, or even both
       = case catMaybes [check_item item, check_item (IEVar data_n)] of
          []     -> bale_out item
-         avails -> returnM (mkAvailEnv avails, emptyGlobalRdrEnv)
+         avails -> returnM (avails, emptyGlobalRdrEnv)
                        -- The GlobalRdrEnv result is irrelevant when hiding
       where
        data_n = setRdrNameSpace n srcDataName
@@ -574,9 +573,8 @@ type ExportAccum    -- The type of the accumulating parameter of
                        -- the main worker function in exportsFromAvail
      = ([ModuleName],          -- 'module M's seen so far
        ExportOccMap,           -- Tracks exported occurrence names
-       AvailEnv)               -- The accumulated exported stuff, kept in an env
-                               --   so we can common-up related AvailInfos
-emptyExportAccum = ([], emptyOccEnv, emptyAvailEnv) 
+       NameSet)                -- The accumulated exported stuff
+emptyExportAccum = ([], emptyOccEnv, emptyNameSet) 
 
 type ExportOccMap = OccEnv (Name, IE RdrName)
        -- Tracks what a particular exported OccName
@@ -587,7 +585,7 @@ type ExportOccMap = OccEnv (Name, IE RdrName)
 
 exportsFromAvail :: Bool  -- False => no 'module M(..) where' header at all
                 -> Maybe [Located (IE RdrName)] -- Nothing => no explicit export list
-                -> RnM Avails
+                -> RnM NameSet
        -- Complains if two distinct exports have same OccName
         -- Warns about identical exports.
        -- Complains about exports items not in scope
@@ -610,33 +608,27 @@ exportsFromAvail explicit_mod exports
        exports_from_avail real_exports rdr_env imports }
 
 
-exports_from_avail Nothing rdr_env
-                  imports@(ImportAvails { imp_env = entity_avail_env })
+exports_from_avail Nothing rdr_env imports
  =     -- Export all locally-defined things
        -- We do this by filtering the global RdrEnv,
-       -- keeping only things that are (a) qualified,
-       -- (b) locally defined, (c) a 'main' name
-       -- Then we look up in the entity-avail-env
-   return [ lookupAvailEnv entity_avail_env name
-         | gre <- globalRdrEnvElts rdr_env,
-           isLocalGRE gre,
-           let name = gre_name gre,
-           isNothing (nameParent_maybe name)   -- Main things only
-         ]
+       -- keeping only things that are locally-defined
+   return (mkNameSet [ gre_name gre 
+                    | gre <- globalRdrEnvElts rdr_env,
+                      isLocalGRE gre ])
 
 exports_from_avail (Just export_items) rdr_env
                   (ImportAvails { imp_qual = mod_avail_env, 
                                   imp_env  = entity_avail_env }) 
   = foldlM (exports_from_litem) emptyExportAccum
-           export_items                        `thenM` \ (_, _, export_avail_map) ->
-    returnM (nameEnvElts export_avail_map)
+           export_items                        `thenM` \ (_, _, exports) ->
+    returnM exports
 
   where
     exports_from_litem :: ExportAccum -> Located (IE RdrName) -> RnM ExportAccum
     exports_from_litem acc = addLocM (exports_from_item acc)
 
     exports_from_item :: ExportAccum -> IE RdrName -> RnM ExportAccum
-    exports_from_item acc@(mods, occs, avails) ie@(IEModuleContents mod)
+    exports_from_item acc@(mods, occs, exports) ie@(IEModuleContents mod)
        | mod `elem` mods       -- Duplicate export of M
        = do { warn_dup_exports <- doptM Opt_WarnDuplicateExports ;
               warnIf warn_dup_exports (dupModuleExport mod) ;
@@ -649,23 +641,19 @@ exports_from_avail (Just export_items) rdr_env
 
            Just avail_env
                -> let
-                       mod_avails = [ filtered_avail
-                                    | avail <- availEnvElts avail_env,
-                                      let mb_avail = filter_unqual rdr_env avail,
-                                      isJust mb_avail,
-                                      let Just filtered_avail = mb_avail]
-                                               
-                       avails' = foldl addAvail avails mod_avails
+                       new_exports = [ name | avail <- availEnvElts avail_env,
+                                              name  <- availNames avail,
+                                              inScopeUnqual rdr_env name ]
                   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 new_exports       `thenM` \ occs' ->
+                  returnM (mod:mods, occs', addListToNameSet exports new_exports)
 
-                  foldlM (check_occs ie) occs mod_avails       `thenM` \ occs' ->
-                  returnM (mod:mods, occs', avails')
-
-    exports_from_item acc@(mods, occs, avails) ie
+    exports_from_item acc@(mods, occs, exports) ie
        = lookupGlobalOccRn (ieName ie)                 `thenM` \ name -> 
          if isUnboundName name then
                returnM acc     -- Avoid error cascade
@@ -684,41 +672,34 @@ exports_from_avail (Just export_items) rdr_env
            Just export_avail ->        
 
                -- Phew!  It's OK!  Now to check the occurrence stuff!
-         checkForDodgyExport ie avail                          `thenM_`
-          check_occs ie occs export_avail                      `thenM` \ occs' ->
-         returnM (mods, occs', addAvail avails export_avail)
+       
+         let 
+             new_exports = availNames export_avail 
+         in
+         checkForDodgyExport ie new_exports            `thenM_`
+          check_occs ie occs new_exports               `thenM` \ occs' ->
+         returnM (mods, occs', addListToNameSet exports new_exports)
          }
 
 
 -------------------------------
-filter_unqual :: GlobalRdrEnv -> AvailInfo -> Maybe AvailInfo
--- Filter the Avail by what's in scope unqualified
-filter_unqual env (Avail n)
-  | in_scope env n = Just (Avail n)
-  | otherwise     = Nothing
-filter_unqual env (AvailTC n ns)
-  | not (null ns') = Just (AvailTC n ns')
-  | otherwise     = Nothing
-  where
-    ns' = filter (in_scope env) ns
-
-in_scope :: GlobalRdrEnv -> Name -> Bool
+inScopeUnqual :: GlobalRdrEnv -> Name -> Bool
 -- Checks whether the Name is in scope unqualified, 
 -- regardless of whether it's ambiguous or not
-in_scope env n = any unQualOK (lookupGRE_Name env n)
+inScopeUnqual env n = any unQualOK (lookupGRE_Name env n)
 
 -------------------------------
-checkForDodgyExport :: IE RdrName -> AvailInfo -> RnM ()
-checkForDodgyExport (IEThingAll tc) (AvailTC _ [n]) = addWarn (dodgyExportWarn tc)
+checkForDodgyExport :: IE RdrName -> [Name] -> RnM ()
+checkForDodgyExport (IEThingAll tc) [n] = addWarn (dodgyExportWarn tc)
   -- This occurs when you import T(..), but
   -- only export T abstractly.  The single [n]
   -- in the AvailTC is the type or class itself
 checkForDodgyExport _ _ = return ()
 
 -------------------------------
-check_occs :: IE RdrName -> ExportOccMap -> AvailInfo -> RnM ExportOccMap
-check_occs ie occs avail 
-  = foldlM check occs (availNames avail)
+check_occs :: IE RdrName -> ExportOccMap -> [Name] -> RnM ExportOccMap
+check_occs ie occs names
+  = foldlM check occs names
   where
     check occs name
       = case lookupOccEnv occs name_occ of
@@ -740,18 +721,77 @@ check_occs ie occs avail
 
 %*********************************************************
 %*                                                      *
-\subsection{Unused names}
+               Deprecations
+%*                                                      *
+%*********************************************************
+
+\begin{code}
+reportDeprecations :: TcGblEnv -> RnM ()
+reportDeprecations tcg_env
+  = ifOptM Opt_WarnDeprecations        $
+    do { (eps,hpt) <- getEpsAndHpt
+       ; mapM_ (check hpt (eps_PIT eps)) all_gres }
+  where
+    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:_) _})
+      | name `elemNameSet` used_names
+      ,        Just deprec_txt <- lookupDeprec hpt pit name
+      = setSrcSpan (is_loc imp_spec) $
+       addWarn (sep [ptext SLIT("Deprecated use of") <+> 
+                       occNameFlavour (nameOccName name) <+> 
+                       quotes (ppr name),
+                     (parens imp_msg),
+                     (ppr deprec_txt) ])
+       where
+         name_mod = nameModuleName name
+         imp_mod  = is_mod 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
+
+    check hpt pit ok_gre = returnM ()  -- Local, or not used, or not deprectated
+           -- The Imported pattern-match: don't deprecate locally defined names
+           -- For a start, we may be exporting a deprecated thing
+           -- Also we may use a deprecated thing in the defn of another
+           -- deprecated things.  We may even use a deprecated thing in
+           -- the defn of a non-deprecated thing, when changing a module's 
+           -- interface
+
+lookupDeprec :: HomePackageTable -> PackageIfaceTable 
+            -> Name -> Maybe DeprecTxt
+lookupDeprec hpt pit n 
+  = case lookupIface hpt pit (nameModule n) of
+       Just iface -> mi_dep_fn iface n `seqMaybe`      -- Bleat if the thing, *or
+                     mi_dep_fn iface (nameParent n)    -- its parent*, is deprec'd
+       Nothing    
+         | isWiredInName n -> Nothing
+               -- We have not necessarily loaded the .hi file for a 
+               -- wired-in name (yet), although we *could*.
+               -- And we never deprecate them
+
+        | otherwise -> pprPanic "lookupDeprec" (ppr n) 
+               -- By now all the interfaces should have been loaded
+
+gre_is_used :: NameSet -> GlobalRdrElt -> Bool
+gre_is_used used_names gre = gre_name gre `elemNameSet` used_names
+\end{code}
+
+%*********************************************************
+%*                                                      *
+               Unused names
 %*                                                      *
 %*********************************************************
 
 \begin{code}
 reportUnusedNames :: TcGblEnv -> RnM ()
 reportUnusedNames gbl_env 
-  = warnUnusedModules unused_imp_mods  `thenM_`
-    warnUnusedTopBinds bad_locals      `thenM_`
-    warnUnusedImports bad_imports      `thenM_`
-    warnDuplicateImports dup_imps      `thenM_`
-    printMinimalImports minimal_imports
+  = do { warnUnusedTopBinds   unused_locals
+       ; warnUnusedModules    unused_imp_mods
+       ; warnUnusedImports    unused_imports   
+       ; warnDuplicateImports dup_imps
+       ; printMinimalImports  minimal_imports }
   where
     used_names, all_used_names :: NameSet
     used_names = findUses (tcg_dus gbl_env) emptyNameSet
@@ -764,28 +804,34 @@ reportUnusedNames gbl_env
     defined_names :: [GlobalRdrElt]
     defined_names = globalRdrEnvElts (tcg_rdr_env gbl_env)
 
+       -- Note that defined_and_used, defined_but_not_used
+       -- are both [GRE]; that's why we need defined_and_used
+       -- rather than just all_used_names
     defined_and_used, defined_but_not_used :: [GlobalRdrElt]
-    (defined_and_used, defined_but_not_used) = partition is_used defined_names
-
-    dup_imps = filter isDupImport defined_and_used
-    is_used gre = gre_name gre `elemNameSet` all_used_names
+    (defined_and_used, defined_but_not_used) 
+       = partition (gre_is_used all_used_names) defined_names
     
-    -- Filter out the ones that are 
-    --  (a) defined in this module, and
-    -- (b) not defined by a 'deriving' clause 
-    -- The latter have an Internal Name, so we can filter them out easily
-    bad_locals :: [GlobalRdrElt]
-    bad_locals = filter is_bad defined_but_not_used
-    is_bad :: GlobalRdrElt -> Bool
-    is_bad gre = isLocalGRE gre && isExternalName (gre_name gre)
+       -- 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 
+       -- The latter have an Internal Name, so we can filter them out easily
+    unused_locals :: [GlobalRdrElt]
+    unused_locals = filter is_unused_local defined_but_not_used
+    is_unused_local :: GlobalRdrElt -> Bool
+    is_unused_local gre = isLocalGRE gre && isExternalName (gre_name gre)
     
-    bad_imports :: [GlobalRdrElt]
-    bad_imports = filter bad_imp defined_but_not_used
-    bad_imp (GRE {gre_prov = Imported imp_specs True}) 
+    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)
                -- Don't complain about unused imports if we've already said the
                -- entire import is unused
-    bad_imp other = False
+    unused_imp other = False
     
     -- 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
@@ -809,12 +855,10 @@ reportUnusedNames gbl_env
        -- There's really no good way to detect this, so the error message 
        -- in RnEnv.warnUnusedModules is weakened instead
     
-
        -- 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 
@@ -825,43 +869,37 @@ reportUnusedNames gbl_env
     mk_avail n Nothing | isTcOcc (nameOccName n) = AvailTC n [n]
                       | otherwise               = Avail n
     
-    add_inst_mod m acc 
-      | m `elemFM` acc = acc   -- We import something already
-      | otherwise      = addToFM acc m emptyAvailEnv
+    add_inst_mod (mod,_,_) acc 
+      | mod_name `elemFM` acc = acc    -- We import something already
+      | otherwise             = addToFM acc mod_name emptyAvailEnv
+      where
+       mod_name = moduleName mod
        -- Add an empty collection of imports for a module
        -- from which we have sucked only instance decls
    
     imports = tcg_imports gbl_env
 
-    direct_import_mods :: [ModuleName]
-    direct_import_mods = map (moduleName . fst) 
-                            (moduleEnvElts (imp_mods imports))
-
-    hasEmptyImpList :: ModuleName -> Bool
-    hasEmptyImpList m = 
-       case lookupModuleEnvByName (imp_mods imports) m of
-        Just (_,Just x) -> not x
-        _ -> False
+    direct_import_mods :: [(Module, Maybe Bool, SrcSpan)]
+       -- See the type of the imp_mods for this triple
+    direct_import_mods = moduleEnvElts (imp_mods imports)
 
     -- unused_imp_mods are the directly-imported modules 
     -- 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 = [m | m <- direct_import_mods,
-                      isNothing (lookupFM minimal_imports1 m),
-                      m /= pRELUDE_Name,
-                      not (hasEmptyImpList m)]
-       -- hasEmptyImpList arranges not to complain about
+    unused_imp_mods = [(mod_name,loc) | (mod,imp,loc) <- direct_import_mods,
+                      let mod_name = moduleName mod,
+                      not (mod_name `elemFM` minimal_imports1),
+                      mod_name /= pRELUDE_Name,
+                      imp /= Just False]
+       -- The Just False part is not to complain about
        -- import M (), which is an idiom for importing
        -- instance declarations
     
     module_unused :: ModuleName -> Bool
-    module_unused mod = mod `elem` unused_imp_mods
-
+    module_unused mod = any (((==) mod) . fst) unused_imp_mods
 
-isDupImport (GRE {gre_prov = Imported imp_spec True}) = not (isSingleton imp_spec)
-isDupImport other                                    = False
-                     
+---------------------
 warnDuplicateImports :: [GlobalRdrElt] -> RnM ()
 warnDuplicateImports gres
   = ifOptM Opt_WarnUnusedImports (mapM_ warn gres)
@@ -966,12 +1004,16 @@ exportClashErr global_env name1 name2 ie1 ie2
             (gre:_) -> gre
             []      -> pprPanic "exportClashErr" (ppr name)
 
-dupDeclErr (n:ns)
-  = vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr n),
-         nest 4 (vcat (map ppr sorted_locs))]
+addDupDeclErr :: [Name] -> TcRn ()
+addDupDeclErr names
+  = addErrAt big_loc $
+    vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr name1),
+         ptext SLIT("Declared at:") <+> vcat (map ppr sorted_locs)]
   where
-    sorted_locs = sortLt occ'ed_before (map nameSrcLoc (n:ns))
-    occ'ed_before a b = LT == compare a b
+    locs    = map nameSrcLoc names
+    big_loc = foldr1 combineSrcSpans (map srcLocSpan locs)
+    name1   = head names
+    sorted_locs = sortLe (<=) (sortLe (<=) locs)
 
 dupExportWarn occ_name ie1 ie2
   = hsep [quotes (ppr occ_name),