+\begin{code}
+reportUnusedNames :: ModIface -> PrintUnqualified
+ -> [RdrNameImportDecl]
+ -> AvailEnv
+ -> NameSet -- Used in this module
+ -> Avails -- Exported by this module
+ -> [RenamedHsDecl]
+ -> RnMG ()
+reportUnusedNames my_mod_iface unqual imports avail_env
+ source_fvs export_avails imported_decls
+ = warnUnusedModules unused_imp_mods `thenRn_`
+ warnUnusedLocalBinds bad_locals `thenRn_`
+ warnUnusedImports bad_imp_names `thenRn_`
+ printMinimalImports this_mod unqual minimal_imports
+ where
+ this_mod = mi_module my_mod_iface
+ gbl_env = mi_globals my_mod_iface
+
+ -- The export_fvs make the exported names look just as if they
+ -- occurred in the source program.
+ export_fvs = availsToNameSet export_avails
+ used_names = source_fvs `plusFV` export_fvs
+
+ -- Now, a use of C implies a use of T,
+ -- if C was brought into scope by T(..) or T(C)
+ really_used_names = used_names `unionNameSets`
+ mkNameSet [ parent_name
+ | sub_name <- nameSetToList used_names
+
+ -- Usually, every used name will appear in avail_env, but there
+ -- is one time when it doesn't: tuples and other built in syntax. When you
+ -- write (a,b) that gives rise to a *use* of "(,)", so that the
+ -- instances will get pulled in, but the tycon "(,)" isn't actually
+ -- in scope. Also, (-x) gives rise to an implicit use of 'negate';
+ -- similarly, 3.5 gives rise to an implcit use of :%
+ -- Hence the silent 'False' in all other cases
+
+ , Just parent_name <- [case lookupNameEnv avail_env sub_name of
+ Just (AvailTC n _) -> Just n
+ other -> Nothing]
+ ]
+
+ -- Collect the defined names from the in-scope environment
+ -- Look for the qualified ones only, else get duplicates
+ defined_names :: [GlobalRdrElt]
+ defined_names = foldRdrEnv add [] gbl_env
+ add rdr_name ns acc | isQual rdr_name = ns ++ acc
+ | otherwise = acc
+
+ defined_and_used, defined_but_not_used :: [GlobalRdrElt]
+ (defined_and_used, defined_but_not_used) = partition used defined_names
+ used (GRE name _ _) = name `elemNameSet` really_used_names
+
+ -- Filter out the ones only defined implicitly
+ bad_locals :: [Name]
+ bad_locals = [n | (GRE n LocalDef _) <- defined_but_not_used]
+
+ bad_imp_names :: [(Name,Provenance)]
+ bad_imp_names = [(n,p) | GRE n p@(NonLocalDef (UserImport mod _ True)) _ <- defined_but_not_used,
+ not (module_unused mod)]
+
+ -- inst_mods are directly-imported modules that
+ -- contain instance decl(s) that the renamer decided to suck in
+ -- It's not necessarily redundant to import such modules.
+ --
+ -- NOTE: Consider
+ -- module This
+ -- import M ()
+ --
+ -- The import M() is not *necessarily* redundant, even if
+ -- we suck in no instance decls from M (e.g. it contains
+ -- no instance decls, or This contains no code). It may be
+ -- that we import M solely to ensure that M's orphan instance
+ -- decls (or those in its imports) are visible to people who
+ -- import This. Sigh.
+ -- There's really no good way to detect this, so the error message
+ -- in RnEnv.warnUnusedModules is weakened instead
+ inst_mods :: [ModuleName]
+ inst_mods = [m | InstD (InstDecl _ _ _ (Just dfun) _) <- imported_decls,
+ let m = moduleName (nameModule dfun),
+ m `elem` direct_import_mods
+ ]
+
+ -- 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
+ minimal_imports :: FiniteMap ModuleName AvailEnv
+ minimal_imports0 = emptyFM
+ minimal_imports1 = foldr add_name minimal_imports0 defined_and_used
+ minimal_imports = foldr add_inst_mod minimal_imports1 inst_mods
+
+ -- 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 n (NonLocalDef (UserImport m _ _)) _) acc = addToFM_C plusAvailEnv acc (moduleName m)
+ (unitAvailEnv (mk_avail n))
+ add_name (GRE n other_prov _) acc = acc
+
+ mk_avail n = case lookupNameEnv avail_env n of
+ Just (AvailTC m _) | n==m -> AvailTC n [n]
+ | otherwise -> AvailTC m [n,m]
+ Just avail -> Avail n
+ Nothing -> pprPanic "mk_avail" (ppr n)
+
+ add_inst_mod m acc
+ | m `elemFM` acc = acc -- We import something already
+ | otherwise = addToFM acc m emptyAvailEnv
+ -- Add an empty collection of imports for a module
+ -- from which we have sucked only instance decls
+
+ direct_import_mods :: [ModuleName]
+ direct_import_mods = nub [m | ImportDecl m _ _ _ _ _ <- imports]
+
+ -- unused_imp_mods are the directly-imported modules
+ -- that are not mentioned in minimal_imports
+ unused_imp_mods = [m | m <- direct_import_mods,
+ not (maybeToBool (lookupFM minimal_imports m)),
+ m /= pRELUDE_Name]
+
+ module_unused :: Module -> Bool
+ module_unused mod = moduleName mod `elem` unused_imp_mods
+
+
+-- ToDo: deal with original imports with 'qualified' and 'as M' clauses
+printMinimalImports :: Module -- This module
+ -> PrintUnqualified
+ -> FiniteMap ModuleName AvailEnv -- Minimal imports
+ -> RnMG ()
+printMinimalImports this_mod unqual imps
+ = doptRn Opt_D_dump_minimal_imports `thenRn` \ dump_minimal ->
+ if not dump_minimal then returnRn () else
+
+ mapRn to_ies (fmToList imps) `thenRn` \ mod_ies ->
+ ioToRnM (do { h <- openFile filename WriteMode ;
+ printForUser h unqual (vcat (map ppr_mod_ie mod_ies))
+ }) `thenRn_`
+ returnRn ()
+ where
+ filename = moduleNameUserString (moduleName this_mod) ++ ".imports"
+ ppr_mod_ie (mod_name, ies)
+ | mod_name == pRELUDE_Name
+ = empty
+ | otherwise
+ = ptext SLIT("import") <+> ppr mod_name <>
+ parens (fsep (punctuate comma (map ppr ies)))
+
+ to_ies (mod, avail_env) = mapRn to_ie (availEnvElts avail_env) `thenRn` \ ies ->
+ returnRn (mod, ies)
+
+ to_ie :: AvailInfo -> RnMG (IE Name)
+ -- The main trick here is that if we're importing all the constructors
+ -- we want to say "T(..)", but if we're importing only a subset we want
+ -- to say "T(A,B,C)". So we have to find out what the module exports.
+ to_ie (Avail n) = returnRn (IEVar n)
+ to_ie (AvailTC n [m]) = ASSERT( n==m )
+ returnRn (IEThingAbs n)
+ to_ie (AvailTC n ns)
+ = loadInterface (text "Compute minimal imports from" <+> ppr n_mod) n_mod ImportBySystem `thenRn` \ iface ->
+ case [xs | (m,as) <- mi_exports iface,
+ m == n_mod,
+ AvailTC x xs <- as,
+ x == n] of
+ [xs] | all (`elem` ns) xs -> returnRn (IEThingAll n)
+ | otherwise -> returnRn (IEThingWith n (filter (/= n) ns))
+ other -> pprTrace "to_ie" (ppr n <+> ppr (nameModule n) <+> ppr other) $
+ returnRn (IEVar n)
+ where
+ n_mod = moduleName (nameModule n)