import Name
import NameEnv
import NameSet
-import OccName ( srcDataName, pprNonVarNameSpace,
- occNameSpace,
- OccEnv, mkOccEnv, lookupOccEnv, emptyOccEnv,
- extendOccEnv )
-import HscTypes ( GenAvailInfo(..), AvailInfo, availNames, availName,
- HomePackageTable, PackageIfaceTable,
- mkPrintUnqualified, availsToNameSet,
- Deprecs(..), ModIface(..), Dependencies(..),
- lookupIfaceByModule, ExternalPackageState(..)
- )
-import RdrName ( RdrName, rdrNameOcc, setRdrNameSpace, Parent(..),
- GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..),
- emptyGlobalRdrEnv, plusGlobalRdrEnv, globalRdrEnvElts,
- extendGlobalRdrEnv, lookupGlobalRdrEnv, lookupGRE_Name,
- Provenance(..), ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..),
- importSpecLoc, importSpecModule, isLocalGRE, pprNameProvenance,
- unQualSpecOK, qualSpecOK )
+import OccName
+import HscTypes
+import RdrName
import Outputable
import Maybes
-import SrcLoc ( Located(..), mkGeneralSrcSpan, getLoc,
- unLoc, noLoc, srcLocSpan, SrcSpan )
+import SrcLoc
import FiniteMap
import ErrUtils
import BasicTypes ( DeprecTxt )
import DriverPhases ( isHsBoot )
import Util
import ListSetOps
-import Data.List ( partition, concatMap )
+import Data.List ( partition, concatMap, (\\), delete )
import IO ( openFile, IOMode(..) )
import Monad ( when )
\end{code}
-- 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
+ let prel_imports = mkPrelImports this_mod implicit_prelude imports
+ (source, ordinary) = partition is_source_import imports
is_source_import (L _ (ImportDecl _ is_boot _ _ _)) = is_boot
- stuff1 <- mapM (rnImportDecl this_mod) ordinary
+ stuff1 <- mapM (rnImportDecl this_mod) (prel_imports ++ ordinary)
stuff2 <- mapM (rnImportDecl this_mod) source
let (decls, rdr_env, imp_avails) = combine (stuff1 ++ stuff2)
return (decls, rdr_env, imp_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_NAME ]
-
combine :: [(LImportDecl Name, GlobalRdrEnv, ImportAvails)]
-> ([LImportDecl Name], GlobalRdrEnv, ImportAvails)
combine = foldr plus ([], emptyGlobalRdrEnv, emptyImportAvails)
gbl_env1 `plusGlobalRdrEnv` gbl_env2,
imp_avails1 `plusImportAvails` imp_avails2)
-preludeImportDecl :: LImportDecl RdrName
-preludeImportDecl
- = L loc $
- ImportDecl (L loc pRELUDE_NAME)
+mkPrelImports :: Module -> Bool -> [LImportDecl RdrName] -> [LImportDecl RdrName]
+-- Consruct the implicit declaration "import Prelude" (or not)
+--
+-- 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.
+mkPrelImports this_mod implicit_prelude import_decls
+ | this_mod == pRELUDE
+ || explicit_prelude_import
+ || not implicit_prelude
+ = []
+ | otherwise = [preludeImportDecl]
+ where
+ explicit_prelude_import
+ = notNull [ () | L _ (ImportDecl mod _ _ _ _) <- import_decls,
+ unLoc mod == pRELUDE_NAME ]
+
+ preludeImportDecl :: LImportDecl RdrName
+ preludeImportDecl
+ = L loc $
+ ImportDecl (L loc pRELUDE_NAME)
False {- Not a boot interface -}
False {- Not qualified -}
Nothing {- No "as" -}
Nothing {- No import list -}
- where
- loc = mkGeneralSrcSpan FSLIT("Implicit import declaration")
-
+ loc = mkGeneralSrcSpan FSLIT("Implicit import declaration")
+
rnImportDecl :: Module
-> LImportDecl RdrName
return (Just (want_hiding, map fst items2), mkGlobalRdrEnv gres)
where
-- This environment is how we map names mentioned in the import
- -- list to the actual Name they correspond to, and the family
- -- that the Name belongs to (an AvailInfo).
+ -- list to the actual Name they correspond to, and the name family
+ -- that the Name belongs to (the AvailInfo). The situation is
+ -- complicated by associated families, which introduce a three-level
+ -- hierachy, where class = grand parent, assoc family = parent, and
+ -- data constructors = children. The occ_env entries for associated
+ -- families needs to capture all this information; hence, we have the
+ -- third component of the environment that gives the class name (=
+ -- grand parent) in case of associated families.
--
-- 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.
- occ_env :: OccEnv (Name,AvailInfo)
- occ_env = mkOccEnv [ (nameOccName n, (n,a))
- | a <- all_avails, n <- availNames a ]
+ occ_env :: OccEnv (Name, -- the name
+ AvailInfo, -- the export item providing the name
+ Maybe Name) -- the parent of associated types
+ occ_env = mkOccEnv_C combine [ (nameOccName n, (n, a, Nothing))
+ | a <- all_avails, n <- availNames a]
+ where
+ -- we know that (1) there are at most entries for one name, (2) their
+ -- first component is identical, (3) they are for tys/cls, and (4) one
+ -- entry has the name in its parent position (the other doesn't)
+ combine (name, AvailTC p1 subs1, Nothing)
+ (_ , AvailTC p2 subs2, Nothing)
+ = let
+ (parent, subs) = if p1 == name then (p2, subs1) else (p1, subs2)
+ in
+ (name, AvailTC name subs, Just parent)
lookup_lie :: Bool -> LIE RdrName -> TcRn [(LIE Name, AvailInfo)]
lookup_lie opt_indexedtypes (L loc ieRdr)
-- Returns Nothing on error.
-- We return a list here, because in the case of an import
-- item like C, if we are hiding, then C refers to *both* a
- -- type/class and a data constructor.
+ -- type/class and a data constructor. Moreover, when we import
+ -- data constructors of an associated family, we need separate
+ -- AvailInfos for the data constructors and the family (as they have
+ -- different parents). See the discussion at occ_env.
lookup_ie :: Bool -> IE RdrName -> MaybeErr Message [(IE Name,AvailInfo)]
lookup_ie opt_indexedtypes ie
= let bad_ie = Failed (badImportItemErr iface decl_spec ie)
in
case ie of
IEVar n -> do
- (name,avail) <- lookup_name n
+ (name, avail, _) <- lookup_name n
return [(IEVar name, trimAvail avail name)]
IEThingAll tc -> do
- (name,avail) <- lookup_name tc
- return [(IEThingAll name, avail)]
+ (name, avail@(AvailTC name2 subs), mb_parent) <- lookup_name tc
+ case mb_parent of
+ -- non-associated ty/cls
+ Nothing -> return [(IEThingAll name, avail)]
+ -- associated ty
+ Just parent -> return [(IEThingAll name,
+ AvailTC name2 (subs \\ [name])),
+ (IEThingAll name, AvailTC parent [name])]
IEThingAbs tc
| want_hiding -- hiding ( C )
in
case catMaybeErr [ tc_name, dc_name ] of
[] -> bad_ie
- names -> return [ (IEThingAbs n, trimAvail av n)
- | (n,av) <- names ]
+ names -> return [mkIEThingAbs name | name <- names]
| otherwise
- -> do (name,avail) <- lookup_name tc
- return [(IEThingAbs name, AvailTC name [name])]
-
- IEThingWith n ns -> do
- (name,avail) <- lookup_name n
- case avail of
- AvailTC nm subnames | nm == name -> do
- let env = mkOccEnv [ (nameOccName s, s)
- | s <- subnames ]
- let mb_children = map (lookupOccEnv env . rdrNameOcc) ns
- children <-
- if any isNothing mb_children
- then bad_ie
- else return (catMaybes mb_children)
- -- check for proper import of indexed types
- when (not opt_indexedtypes && any isTyConName children) $
- Failed (typeItemErr (head . filter isTyConName
- $ children )
- (text "in import list"))
- return [(IEThingWith name children, AvailTC name (name:children))]
-
- _otherwise -> bad_ie
+ -> do nameAvail <- lookup_name tc
+ return [mkIEThingAbs nameAvail]
+
+ IEThingWith tc ns -> do
+ (name, AvailTC name2 subnames, mb_parent) <- lookup_name tc
+ let
+ env = mkOccEnv [(nameOccName s, s) | s <- subnames]
+ mb_children = map (lookupOccEnv env . rdrNameOcc) ns
+ children <- if any isNothing mb_children
+ then bad_ie
+ else return (catMaybes mb_children)
+ -- check for proper import of indexed types
+ when (not opt_indexedtypes && any isTyConName children) $
+ Failed (typeItemErr (head . filter isTyConName $ children)
+ (text "in import list"))
+ case mb_parent of
+ -- non-associated ty/cls
+ Nothing -> return [(IEThingWith name children,
+ AvailTC name (name:children))]
+ -- associated ty
+ Just parent -> return [(IEThingWith name children,
+ AvailTC name children),
+ (IEThingWith name children,
+ AvailTC parent [name])]
_other -> Failed illegalImportItemErr
-- could be IEModuleContents, IEGroup, IEDoc, IEDocNamed
-- all errors.
+ where
+ mkIEThingAbs (n, av, Nothing ) = (IEThingAbs n, trimAvail av n)
+ mkIEThingAbs (n, av, Just parent) = (IEThingAbs n, AvailTC parent [n])
+
+
catMaybeErr :: [MaybeErr err a] -> [a]
catMaybeErr ms = [ a | Succeeded a <- ms ]
\end{code}
-- We want to combine these; addAvail does that
mkAvailEnv avails = foldl addAvail emptyAvailEnv avails
+-- After combining the avails, we need to ensure that the parent name is the
+-- first entry in the list of subnames, if it is included at all. (Subsequent
+-- functions rely on that.)
+normaliseAvail :: AvailInfo -> AvailInfo
+normaliseAvail avail@(Avail _) = avail
+normaliseAvail (AvailTC name subs) = AvailTC name subs'
+ where
+ subs' = if name `elem` subs then name : (delete name subs) else subs
+
-- | combines 'AvailInfo's from the same family
nubAvails :: [AvailInfo] -> [AvailInfo]
-nubAvails avails = nameEnvElts (mkAvailEnv avails)
+nubAvails avails = map normaliseAvail . nameEnvElts . mkAvailEnv $ avails
\end{code}
exports_from_avail (Just rdr_items) rdr_env imports this_mod
= do (ie_names, _, exports) <- foldlM do_litem emptyExportAccum rdr_items
+
return (Just ie_names, exports)
where
do_litem :: ExportAccum -> LIE RdrName -> RnM ExportAccum
return (IEVar (gre_name gre), greAvail gre)
lookup_ie (IEThingAbs rdr)
- = do name <- lookupGlobalOccRn rdr
- return (IEThingAbs name, AvailTC name [name])
+ = do gre <- lookupGreRn rdr
+ let name = gre_name gre
+ case gre_par gre of
+ NoParent -> return (IEThingAbs name,
+ AvailTC name [name])
+ ParentIs p -> return (IEThingAbs name,
+ AvailTC p [name])
lookup_ie ie@(IEThingAll rdr)
= do name <- lookupGlobalOccRn rdr
check hpt pit gre@(GRE {gre_name = name, gre_prov = Imported (imp_spec:_)})
| name `elemNameSet` used_names
- , Just deprec_txt <- lookupDeprec dflags hpt pit gre
+ , Just deprec_txt <- lookupImpDeprec dflags hpt pit gre
= addWarnAt (importSpecLoc imp_spec)
(sep [ptext SLIT("Deprecated use of") <+>
pprNonVarNameSpace (occNameSpace (nameOccName name)) <+>
-- the defn of a non-deprecated thing, when changing a module's
-- interface
-lookupDeprec :: DynFlags -> HomePackageTable -> PackageIfaceTable
- -> GlobalRdrElt -> Maybe DeprecTxt
-lookupDeprec dflags hpt pit gre
+lookupImpDeprec :: DynFlags -> HomePackageTable -> PackageIfaceTable
+ -> GlobalRdrElt -> Maybe DeprecTxt
+-- The name is definitely imported, so look in HPT, PIT
+lookupImpDeprec dflags hpt pit gre
= case lookupIfaceByModule dflags hpt pit (nameModule name) of
Just iface -> mi_dep_fn iface name `seqMaybe` -- Bleat if the thing, *or
case gre_par gre of
is_unused_local :: GlobalRdrElt -> Bool
is_unused_local gre = isLocalGRE gre && isExternalName (gre_name gre)
- unused_imports :: [GlobalRdrElt]
- unused_imports = filter unused_imp defined_but_not_used
- 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
+ unused_imports :: [GlobalRdrElt]
+ unused_imports = mapCatMaybes unused_imp defined_but_not_used
+ unused_imp :: GlobalRdrElt -> Maybe GlobalRdrElt -- Result has trimmed Imported provenances
+ unused_imp gre@(GRE {gre_prov = LocalDef}) = Nothing
+ unused_imp gre@(GRE {gre_prov = Imported imp_specs})
+ | null trimmed_specs = Nothing
+ | otherwise = Just (gre {gre_prov = Imported trimmed_specs})
+ where
+ trimmed_specs = filter report_if_unused imp_specs
-- 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
--
-- 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 :: [(ModuleName, SrcSpan)]
unused_imp_mods = [(mod_name,loc) | (mod,no_imp,loc) <- direct_import_mods,
let mod_name = moduleName mod,
not (mod_name `elemFM` minimal_imports1),
module_unused :: ModuleName -> Bool
module_unused mod = any (((==) mod) . fst) unused_imp_mods
+ report_if_unused :: ImportSpec -> Bool
+ -- Do we want to report this as an unused import?
+ report_if_unused (ImpSpec {is_decl = d, is_item = i})
+ = not (module_unused (is_mod d)) -- Not if we've already said entire import is unused
+ && isExplicitItem i -- Only if the import was explicit
+
---------------------
warnDuplicateImports :: [GlobalRdrElt] -> RnM ()
-- Given the GREs for names that are used, figure out which imports
warnDuplicateImports 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
redundants imps
= [ (red_imp, cov_imp)
| red_imp <- imps
+ , isExplicitItem (is_item red_imp)
+ -- Complain only about redundant imports
+ -- mentioned explicitly by the user
, cov_imp <- take 1 (filter (covers red_imp) imps) ]
+ -- The 'take 1' picks the first offending group
+ -- for this particular name
-- "red_imp" is a putative redundant import
-- "cov_imp" potentially covers it
= 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
+ | otherwise
+ = not (isExplicitItem cov_item) -- Redundant one is selective and covering one isn't
+ || red_later -- or both are explicit; tie-break using red_later
+{-
| red_selective
= not cov_selective -- Redundant one is selective and covering one isn't
|| red_later -- Both are explicit; tie-break using red_later
= 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 ModuleName AvailEnv -- Minimal imports