\begin{code}
module RnNames (
rnImports, importsFromLocalDecls, exportsFromAvail,
- reportUnusedNames, mkModDeps, exportsToAvails
+ reportUnusedNames, reportDeprecations,
+ mkModDeps, exportsToAvails
) where
#include "HsVersions.h"
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 ( OccName, srcDataName, isTcOcc, OccEnv, elemOccEnv,
+import OccName ( srcDataName, isTcOcc, occNameFlavour, OccEnv,
mkOccEnv, lookupOccEnv, emptyOccEnv, extendOccEnv )
import HscTypes ( GenAvailInfo(..), AvailInfo, Avails, GhciMode(..),
- IsBootInterface, IfaceExport,
+ IfaceExport, HomePackageTable, PackageIfaceTable,
availName, availNames, availsToNameSet, unQualInScope,
- Deprecs(..), ModIface(..), Dependencies(..)
+ Deprecs(..), ModIface(..), Dependencies(..), lookupIface,
+ ExternalPackageState(..)
)
import RdrName ( RdrName, rdrNameOcc, setRdrNameSpace,
GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..),
Provenance(..), ImportSpec(..),
isLocalGRE, pprNameProvenance )
import Outputable
-import Maybes ( isJust, isNothing, catMaybes, mapCatMaybes )
+import Maybes ( isJust, isNothing, catMaybes, mapCatMaybes, seqMaybe )
import SrcLoc ( noSrcLoc, Located(..), mkGeneralSrcSpan,
- unLoc, noLoc )
+ unLoc, noLoc, srcLocSpan, 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}
-> 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
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
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)
= -- 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))
+ ASSERT( not (mi_package iface `elem` dep_pkgs deps) )
+ ([], mi_package iface : dep_pkgs deps)
not_self (m, _) = m /= this_mod_name
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 }
-- 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
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 {
-> 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)
-- 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
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
-- 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
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
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) ;
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
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
%*********************************************************
%* *
-\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
+ = addSrcSpan (is_loc imp_spec) $
+ addWarn (sep [ptext SLIT("Deprecated use of") <+>
+ text (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
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
-- 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
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)
(gre:_) -> gre
[] -> pprPanic "exportClashErr" (ppr name)
-dupDeclErr (n:ns)
- = vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr n),
+addDupDeclErr :: [Name] -> TcRn ()
+addDupDeclErr (n:ns)
+ = addErrAt (srcLocSpan (nameSrcLoc n)) $
+ vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr n),
+ nest 2 (ptext SLIT("other declarations at:")),
nest 4 (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
+ sorted_locs = sortLe occ'ed_before (map nameSrcLoc ns)
+ occ'ed_before a b = case compare a b of
+ LT -> True
+ EQ -> True
+ GT -> False
dupExportWarn occ_name ie1 ie2
= hsep [quotes (ppr occ_name),