Commit 6353efc7 authored by David Eichmann's avatar David Eichmann 🏋 Committed by Ben Gamari

Fix unused-import warnings

This patch fixes a fairly long-standing bug (dating back to 2015) in
RdrName.bestImport, namely

   commit 9376249b
   Author: Simon Peyton Jones <simonpj@microsoft.com>
   Date:   Wed Oct 28 17:16:55 2015 +0000

   Fix unused-import stuff in a better way

In that patch got the sense of the comparison back to front, and
thereby failed to implement the unused-import rules described in
  Note [Choosing the best import declaration] in RdrName

This led to Trac #13064 and #15393

Fixing this bug revealed a bunch of unused imports in libraries;
the ones in the GHC repo are part of this commit.

The two important changes are

* Fix the bug in bestImport

* Modified the rules by adding (a) in
     Note [Choosing the best import declaration] in RdrName
  Reason: the previosu rules made Trac #5211 go bad again.  And
  the new rule (a) makes sense to me.

In unravalling this I also ended up doing a few other things

* Refactor RnNames.ImportDeclUsage to use a [GlobalRdrElt] for the
  things that are used, rather than [AvailInfo]. This is simpler
  and more direct.

* Rename greParentName to greParent_maybe, to follow GHC
  naming conventions

* Delete dead code RdrName.greUsedRdrName

Bumps a few submodules.

Reviewers: hvr, goldfire, bgamari, simonmar, jrtc27

Subscribers: rwbarton, carter

Differential Revision: https://phabricator.haskell.org/D5312
parent 8d008b71
...@@ -53,14 +53,14 @@ module RdrName ( ...@@ -53,14 +53,14 @@ module RdrName (
-- * GlobalRdrElts -- * GlobalRdrElts
gresFromAvails, gresFromAvail, localGREsFromAvail, availFromGRE, gresFromAvails, gresFromAvail, localGREsFromAvail, availFromGRE,
greUsedRdrName, greRdrNames, greSrcSpan, greQualModName, greRdrNames, greSrcSpan, greQualModName,
gresToAvailInfo, gresToAvailInfo,
-- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec' -- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec'
GlobalRdrElt(..), isLocalGRE, isRecFldGRE, greLabel, GlobalRdrElt(..), isLocalGRE, isRecFldGRE, greLabel,
unQualOK, qualSpecOK, unQualSpecOK, unQualOK, qualSpecOK, unQualSpecOK,
pprNameProvenance, pprNameProvenance,
Parent(..), Parent(..), greParent_maybe,
ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..), ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..),
importSpecLoc, importSpecModule, isExplicitItem, bestImport, importSpecLoc, importSpecModule, isExplicitItem, bestImport,
...@@ -657,18 +657,6 @@ greQualModName gre@(GRE { gre_name = name, gre_lcl = lcl, gre_imp = iss }) ...@@ -657,18 +657,6 @@ greQualModName gre@(GRE { gre_name = name, gre_lcl = lcl, gre_imp = iss })
| (is:_) <- iss = is_as (is_decl is) | (is:_) <- iss = is_as (is_decl is)
| otherwise = pprPanic "greQualModName" (ppr gre) | otherwise = pprPanic "greQualModName" (ppr gre)
greUsedRdrName :: GlobalRdrElt -> RdrName
-- For imported things, return a RdrName to add to the used-RdrName
-- set, which is used to generate unused-import-decl warnings.
-- Return a Qual RdrName if poss, so that identifies the most
-- specific ImportSpec. See Trac #10890 for some good examples.
greUsedRdrName gre@GRE{ gre_name = name, gre_lcl = lcl, gre_imp = iss }
| lcl, Just mod <- nameModule_maybe name = Qual (moduleName mod) occ
| not (null iss), is <- bestImport iss = Qual (is_as (is_decl is)) occ
| otherwise = pprTrace "greUsedRdrName" (ppr gre) (Unqual occ)
where
occ = greOccName gre
greRdrNames :: GlobalRdrElt -> [RdrName] greRdrNames :: GlobalRdrElt -> [RdrName]
greRdrNames gre@GRE{ gre_lcl = lcl, gre_imp = iss } greRdrNames gre@GRE{ gre_lcl = lcl, gre_imp = iss }
= (if lcl then [unqual] else []) ++ concatMap do_spec (map is_decl iss) = (if lcl then [unqual] else []) ++ concatMap do_spec (map is_decl iss)
...@@ -696,11 +684,11 @@ mkParent _ (Avail _) = NoParent ...@@ -696,11 +684,11 @@ mkParent _ (Avail _) = NoParent
mkParent n (AvailTC m _ _) | n == m = NoParent mkParent n (AvailTC m _ _) | n == m = NoParent
| otherwise = ParentIs m | otherwise = ParentIs m
greParentName :: GlobalRdrElt -> Maybe Name greParent_maybe :: GlobalRdrElt -> Maybe Name
greParentName gre = case gre_par gre of greParent_maybe gre = case gre_par gre of
NoParent -> Nothing NoParent -> Nothing
ParentIs n -> Just n ParentIs n -> Just n
FldParent n _ -> Just n FldParent n _ -> Just n
-- | Takes a list of distinct GREs and folds them -- | Takes a list of distinct GREs and folds them
-- into AvailInfos. This is more efficient than mapping each individual -- into AvailInfos. This is more efficient than mapping each individual
...@@ -716,7 +704,7 @@ gresToAvailInfo gres ...@@ -716,7 +704,7 @@ gresToAvailInfo gres
add :: NameEnv AvailInfo -> GlobalRdrElt -> NameEnv AvailInfo add :: NameEnv AvailInfo -> GlobalRdrElt -> NameEnv AvailInfo
add env gre = extendNameEnv_Acc comb availFromGRE env add env gre = extendNameEnv_Acc comb availFromGRE env
(fromMaybe (gre_name gre) (fromMaybe (gre_name gre)
(greParentName gre)) gre (greParent_maybe gre)) gre
where where
-- We want to insert the child `k` into a list of children but -- We want to insert the child `k` into a list of children but
...@@ -1192,10 +1180,7 @@ instance Ord ImpItemSpec where ...@@ -1192,10 +1180,7 @@ instance Ord ImpItemSpec where
bestImport :: [ImportSpec] -> ImportSpec bestImport :: [ImportSpec] -> ImportSpec
-- Given a non-empty bunch of ImportSpecs, return the one that -- See Note [Choosing the best import declaration]
-- imported the item most specifically (e.g. by name), using
-- textually-first as a tie breaker. This is used when reporting
-- redundant imports
bestImport iss bestImport iss
= case sortBy best iss of = case sortBy best iss of
(is:_) -> is (is:_) -> is
...@@ -1203,17 +1188,76 @@ bestImport iss ...@@ -1203,17 +1188,76 @@ bestImport iss
where where
best :: ImportSpec -> ImportSpec -> Ordering best :: ImportSpec -> ImportSpec -> Ordering
-- Less means better -- Less means better
-- Unqualified always wins over qualified; then
-- import-all wins over import-some; then
-- earlier declaration wins over later
best (ImpSpec { is_item = item1, is_decl = d1 }) best (ImpSpec { is_item = item1, is_decl = d1 })
(ImpSpec { is_item = item2, is_decl = d2 }) (ImpSpec { is_item = item2, is_decl = d2 })
= best_item item1 item2 `thenCmp` (is_dloc d1 `compare` is_dloc d2) = (is_qual d1 `compare` is_qual d2) `thenCmp`
(best_item item1 item2) `thenCmp`
(is_dloc d1 `compare` is_dloc d2)
best_item :: ImpItemSpec -> ImpItemSpec -> Ordering best_item :: ImpItemSpec -> ImpItemSpec -> Ordering
best_item ImpAll ImpAll = EQ best_item ImpAll ImpAll = EQ
best_item ImpAll (ImpSome {}) = GT best_item ImpAll (ImpSome {}) = LT
best_item (ImpSome {}) ImpAll = LT best_item (ImpSome {}) ImpAll = GT
best_item (ImpSome { is_explicit = e1 }) best_item (ImpSome { is_explicit = e1 })
(ImpSome { is_explicit = e2 }) = e2 `compare` e1 (ImpSome { is_explicit = e2 }) = e1 `compare` e2
-- False < True, so if e1 is explicit and e2 is not, we get LT -- False < True, so if e1 is explicit and e2 is not, we get GT
{- Note [Choosing the best import declaration]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When reporting unused import declarations we use the following rules.
(see [wiki:Commentary/Compiler/UnusedImports])
Say that an import-item is either
* an entire import-all decl (eg import Foo), or
* a particular item in an import list (eg import Foo( ..., x, ...)).
The general idea is that for each /occurrence/ of an imported name, we will
attribute that use to one import-item. Once we have processed all the
occurrences, any import items with no uses attributed to them are unused,
and are warned about. More precisely:
1. For every RdrName in the program text, find its GlobalRdrElt.
2. Then, from the [ImportSpec] (gre_imp) of that GRE, choose one
the "chosen import-item", and mark it "used". This is done
by 'bestImport'
3. After processing all the RdrNames, bleat about any
import-items that are unused.
This is done in RnNames.warnUnusedImportDecls.
The function 'bestImport' returns the dominant import among the
ImportSpecs it is given, implementing Step 2. We say import-item A
dominates import-item B if we choose A over B. In general, we try to
choose the import that is most likely to render other imports
unnecessary. Here is the dominance relationship we choose:
a) import Foo dominates import qualified Foo.
b) import Foo dominates import Foo(x).
c) Otherwise choose the textually first one.
Rationale for (a). Consider
import qualified M -- Import #1
import M( x ) -- Import #2
foo = M.x + x
The unqualified 'x' can only come from import #2. The qualified 'M.x'
could come from either, but bestImport picks import #2, because it is
more likely to be useful in other imports, as indeed it is in this
case (see Trac #5211 for a concrete example).
But the rules are not perfect; consider
import qualified M -- Import #1
import M( x ) -- Import #2
foo = M.x + M.y
The M.x will use import #2, but M.y can only use import #1.
-}
unQualSpecOK :: ImportSpec -> Bool unQualSpecOK :: ImportSpec -> Bool
-- ^ Is in scope unqualified? -- ^ Is in scope unqualified?
......
...@@ -21,7 +21,6 @@ import SMRep ...@@ -21,7 +21,6 @@ import SMRep
import DynFlags import DynFlags
import Util import Util
import Data.Foldable (foldl')
import Data.Bits import Data.Bits
{-| {-|
......
...@@ -29,7 +29,6 @@ import qualified TrieMap as TM ...@@ -29,7 +29,6 @@ import qualified TrieMap as TM
import UniqFM import UniqFM
import Unique import Unique
import Control.Arrow (first, second) import Control.Arrow (first, second)
import Data.List (foldl')
-- ----------------------------------------------------------------------------- -- -----------------------------------------------------------------------------
-- Eliminate common blocks -- Eliminate common blocks
......
...@@ -37,7 +37,7 @@ import qualified Data.Set as Set ...@@ -37,7 +37,7 @@ import qualified Data.Set as Set
import Control.Monad.Fix import Control.Monad.Fix
import Data.Array as Array import Data.Array as Array
import Data.Bits import Data.Bits
import Data.List (nub, foldl') import Data.List (nub)
{- Note [Stack Layout] {- Note [Stack Layout]
......
...@@ -19,7 +19,7 @@ import CmmUtils ...@@ -19,7 +19,7 @@ import CmmUtils
import CmmInfo import CmmInfo
import CmmLive import CmmLive
import CmmSwitch import CmmSwitch
import Data.List (sortBy, foldl') import Data.List (sortBy)
import Maybes import Maybes
import Control.Monad import Control.Monad
import Outputable import Outputable
......
...@@ -17,7 +17,7 @@ import GhcPrelude ...@@ -17,7 +17,7 @@ import GhcPrelude
import qualified Data.IntMap.Strict as M import qualified Data.IntMap.Strict as M
import qualified Data.IntSet as S import qualified Data.IntSet as S
import Data.List (foldl', foldl1') import Data.List (foldl1')
class IsSet set where class IsSet set where
type ElemOf set type ElemOf set
......
...@@ -35,7 +35,6 @@ import Cmm ...@@ -35,7 +35,6 @@ import Cmm
import CmmUtils import CmmUtils
import CLabel import CLabel
import qualified Module
import CostCentre import CostCentre
import DynFlags import DynFlags
import FastString import FastString
......
...@@ -32,7 +32,7 @@ import PprCore ( pprCoreBindings, pprRules ) ...@@ -32,7 +32,7 @@ import PprCore ( pprCoreBindings, pprRules )
import OccurAnal( occurAnalyseExpr, occurAnalysePgm ) import OccurAnal( occurAnalyseExpr, occurAnalysePgm )
import Literal ( Literal(LitString) ) import Literal ( Literal(LitString) )
import Id import Id
import Var ( varType, isNonCoVarId ) import Var ( isNonCoVarId )
import VarSet import VarSet
import VarEnv import VarEnv
import DataCon import DataCon
......
...@@ -60,7 +60,7 @@ import Name ( NamedThing(..), nameSrcSpan ) ...@@ -60,7 +60,7 @@ import Name ( NamedThing(..), nameSrcSpan )
import SrcLoc ( SrcSpan(..), realSrcLocSpan, mkRealSrcLoc ) import SrcLoc ( SrcSpan(..), realSrcLocSpan, mkRealSrcLoc )
import Data.Bits import Data.Bits
import MonadUtils ( mapAccumLM ) import MonadUtils ( mapAccumLM )
import Data.List ( mapAccumL, foldl' ) import Data.List ( mapAccumL )
import Control.Monad import Control.Monad
import CostCentre ( CostCentre, ccFromThisModule ) import CostCentre ( CostCentre, ccFromThisModule )
import qualified Data.Set as S import qualified Data.Set as S
......
...@@ -21,8 +21,6 @@ import Var ...@@ -21,8 +21,6 @@ import Var
import Type (Type, typeSize) import Type (Type, typeSize)
import Id (isJoinId) import Id (isJoinId)
import Data.List (foldl')
data CoreStats = CS { cs_tm :: !Int -- Terms data CoreStats = CS { cs_tm :: !Int -- Terms
, cs_ty :: !Int -- Types , cs_ty :: !Int -- Types
, cs_co :: !Int -- Coercions , cs_co :: !Int -- Coercions
......
...@@ -53,7 +53,7 @@ import Name ...@@ -53,7 +53,7 @@ import Name
import VarSet import VarSet
import Rules import Rules
import VarEnv import VarEnv
import Var( EvVar, varType ) import Var( EvVar )
import Outputable import Outputable
import Module import Module
import SrcLoc import SrcLoc
......
...@@ -41,7 +41,6 @@ import Util ...@@ -41,7 +41,6 @@ import Util
-- Standard libraries -- Standard libraries
import Data.Array.Unboxed import Data.Array.Unboxed
import Foreign.Ptr import Foreign.Ptr
import GHC.IO ( IO(..) )
import GHC.Exts import GHC.Exts
{- {-
......
...@@ -57,16 +57,15 @@ import TysWiredIn ...@@ -57,16 +57,15 @@ import TysWiredIn
import DynFlags import DynFlags
import Outputable as Ppr import Outputable as Ppr
import GHC.Char import GHC.Char
import GHC.Exts
import GHC.Exts.Heap import GHC.Exts.Heap
import GHC.IO ( IO(..) )
import SMRep ( roundUpTo ) import SMRep ( roundUpTo )
import Control.Monad import Control.Monad
import Data.Array.Base
import Data.Maybe import Data.Maybe
import Data.List import Data.List
#if defined(INTEGER_GMP) #if defined(INTEGER_GMP)
import GHC.Exts
import Data.Array.Base
import GHC.Integer.GMP.Internals import GHC.Integer.GMP.Internals
#endif #endif
import qualified Data.Sequence as Seq import qualified Data.Sequence as Seq
......
...@@ -22,7 +22,6 @@ import RdrName ...@@ -22,7 +22,6 @@ import RdrName
import qualified Name import qualified Name
import Module import Module
import RdrHsSyn import RdrHsSyn
import qualified OccName
import OccName import OccName
import SrcLoc import SrcLoc
import Type import Type
......
...@@ -44,7 +44,6 @@ import DynFlags ...@@ -44,7 +44,6 @@ import DynFlags
import Data.Data hiding ( Fixity ) import Data.Data hiding ( Fixity )
import Data.List hiding ( foldr ) import Data.List hiding ( foldr )
import Data.Ord import Data.Ord
import Data.Foldable ( Foldable(..) )
{- {-
************************************************************************ ************************************************************************
......
...@@ -18,7 +18,6 @@ module HsExtension where ...@@ -18,7 +18,6 @@ module HsExtension where
import GhcPrelude import GhcPrelude
import GHC.Exts (Constraint)
import Data.Data hiding ( Fixity ) import Data.Data hiding ( Fixity )
import PlaceHolder import PlaceHolder
import Name import Name
......
...@@ -281,6 +281,9 @@ ieWrappedName (IEName (L _ n)) = n ...@@ -281,6 +281,9 @@ ieWrappedName (IEName (L _ n)) = n
ieWrappedName (IEPattern (L _ n)) = n ieWrappedName (IEPattern (L _ n)) = n
ieWrappedName (IEType (L _ n)) = n ieWrappedName (IEType (L _ n)) = n
lieWrappedName :: LIEWrappedName name -> name
lieWrappedName (L _ n) = ieWrappedName n
ieLWrappedName :: LIEWrappedName name -> Located name ieLWrappedName :: LIEWrappedName name -> Located name
ieLWrappedName (L l n) = L l (ieWrappedName n) ieLWrappedName (L l n) = L l (ieWrappedName n)
......
...@@ -90,7 +90,6 @@ import FastString ...@@ -90,7 +90,6 @@ import FastString
import Maybes( isJust ) import Maybes( isJust )
import Data.Data hiding ( Fixity, Prefix, Infix ) import Data.Data hiding ( Fixity, Prefix, Infix )
import Data.List ( foldl' )
import Data.Maybe ( fromMaybe ) import Data.Maybe ( fromMaybe )
{- {-
......
...@@ -38,7 +38,6 @@ import Util ...@@ -38,7 +38,6 @@ import Util
import Control.Monad.Trans.Class import Control.Monad.Trans.Class
import Control.Monad.Trans.Writer import Control.Monad.Trans.Writer
import Data.Semigroup ( Semigroup )
import qualified Data.Semigroup as Semigroup import qualified Data.Semigroup as Semigroup
import Data.List ( nub ) import Data.List ( nub )
import Data.Maybe ( catMaybes ) import Data.Maybe ( catMaybes )
......
...@@ -34,7 +34,6 @@ module Ar ...@@ -34,7 +34,6 @@ module Ar
import GhcPrelude import GhcPrelude
import Data.Semigroup (Semigroup)
import Data.List (mapAccumL, isPrefixOf) import Data.List (mapAccumL, isPrefixOf)
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.Binary.Get import Data.Binary.Get
......
...@@ -248,7 +248,9 @@ import qualified EnumSet ...@@ -248,7 +248,9 @@ import qualified EnumSet
import GHC.Foreign (withCString, peekCString) import GHC.Foreign (withCString, peekCString)
import qualified GHC.LanguageExtensions as LangExt import qualified GHC.LanguageExtensions as LangExt
#if defined(GHCI)
import Foreign (Ptr) -- needed for 2nd stage import Foreign (Ptr) -- needed for 2nd stage
#endif
-- Note [Updating flag description in the User's Guide] -- Note [Updating flag description in the User's Guide]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
...@@ -25,7 +25,6 @@ module DynamicLoading ( ...@@ -25,7 +25,6 @@ module DynamicLoading (
) where ) where
import GhcPrelude import GhcPrelude
import HscTypes ( HscEnv )
import DynFlags import DynFlags
#if defined(GHCI) #if defined(GHCI)
...@@ -63,6 +62,7 @@ import GHC.Exts ( unsafeCoerce# ) ...@@ -63,6 +62,7 @@ import GHC.Exts ( unsafeCoerce# )
#else #else
import HscTypes ( HscEnv )
import Module ( ModuleName, moduleNameString ) import Module ( ModuleName, moduleNameString )
import Panic import Panic
...@@ -76,12 +76,13 @@ import Control.Monad ( unless ) ...@@ -76,12 +76,13 @@ import Control.Monad ( unless )
-- actual compilation starts. Idempotent operation. Should be re-called if -- actual compilation starts. Idempotent operation. Should be re-called if
-- pluginModNames or pluginModNameOpts changes. -- pluginModNames or pluginModNameOpts changes.
initializePlugins :: HscEnv -> DynFlags -> IO DynFlags initializePlugins :: HscEnv -> DynFlags -> IO DynFlags
initializePlugins hsc_env df
#if !defined(GHCI) #if !defined(GHCI)
initializePlugins _ df
= do let pluginMods = pluginModNames df = do let pluginMods = pluginModNames df
unless (null pluginMods) (pluginError pluginMods) unless (null pluginMods) (pluginError pluginMods)
return df return df
#else #else
initializePlugins hsc_env df
| map lpModuleName (plugins df) == pluginModNames df -- plugins not changed | map lpModuleName (plugins df) == pluginModNames df -- plugins not changed
&& all (\p -> lpArguments p == argumentsForPlugin p (pluginModNameOpts df)) && all (\p -> lpArguments p == argumentsForPlugin p (pluginModNameOpts df))
(plugins df) -- arguments not changed (plugins df) -- arguments not changed
......
...@@ -50,7 +50,6 @@ import System.Directory ...@@ -50,7 +50,6 @@ import System.Directory
import System.FilePath import System.FilePath
import Control.Monad import Control.Monad
import Data.Time import Data.Time
import Data.List ( foldl' )
type FileExt = String -- Filename extension type FileExt = String -- Filename extension
......
...@@ -291,7 +291,6 @@ import GhcPrelude hiding (init) ...@@ -291,7 +291,6 @@ import GhcPrelude hiding (init)
import ByteCodeTypes import ByteCodeTypes
import InteractiveEval import InteractiveEval
import InteractiveEvalTypes import InteractiveEvalTypes
import TcRnDriver ( runTcInteractive )
import GHCi import GHCi
import GHCi.RemoteTypes import GHCi.RemoteTypes
...@@ -359,7 +358,6 @@ import Data.Set (Set) ...@@ -359,7 +358,6 @@ import Data.Set (Set)
import qualified Data.Sequence as Seq import qualified Data.Sequence as Seq
import System.Directory ( doesFileExist ) import System.Directory ( doesFileExist )
import Data.Maybe import Data.Maybe
import Data.List ( find )
import Data.Time import Data.Time
import Data.Typeable ( Typeable ) import Data.Typeable ( Typeable )
import Data.Word ( Word8 ) import Data.Word ( Word8 )
......
...@@ -85,7 +85,6 @@ module HscMain ...@@ -85,7 +85,6 @@ module HscMain
import GhcPrelude import GhcPrelude
import Data.Data hiding (Fixity, TyCon) import Data.Data hiding (Fixity, TyCon)
import DynFlags (addPluginModuleName)
import Id import Id
import GHCi ( addSptEntry ) import GHCi ( addSptEntry )
import GHCi.RemoteTypes ( ForeignHValue ) import GHCi.RemoteTypes ( ForeignHValue )
......
...@@ -17,7 +17,6 @@ import SrcLoc ...@@ -17,7 +17,6 @@ import SrcLoc
import Util import Util
import Data.Char import Data.Char
import Data.Foldable (foldl')
-- | Source Statistics -- | Source Statistics
ppSourceStats :: Bool -> Located (HsModule GhcPs) -> SDoc ppSourceStats :: Bool -> Located (HsModule GhcPs) -> SDoc
......
...@@ -95,7 +95,6 @@ import Data.List as List ...@@ -95,7 +95,6 @@ import Data.List as List
import Data.Map (Map) import Data.Map (Map)
import Data.Set (Set) import