X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2Frename%2FRnNames.lhs;h=8b09f52a9a9b7d9cdba2f3b63248ce9ed75f8b98;hp=29468fd0bae75528815d85bf471b02f08fe63d26;hb=c1681a73fa4ca4cf8758264ae387ac09a9e900d8;hpb=311b1cdfc9b1c311cc53482c461c18cba8885b2a diff --git a/compiler/rename/RnNames.lhs b/compiler/rename/RnNames.lhs index 29468fd..8b09f52 100644 --- a/compiler/rename/RnNames.lhs +++ b/compiler/rename/RnNames.lhs @@ -8,56 +8,41 @@ module RnNames ( rnImports, importsFromLocalDecls, rnExports, getLocalDeclBinders, extendRdrEnvRn, - reportUnusedNames, reportDeprecations + reportUnusedNames, finishDeprecations ) where #include "HsVersions.h" -import DynFlags ( DynFlag(..), GhcMode(..), DynFlags(..) ) +import DynFlags import HsSyn ( IE(..), ieName, ImportDecl(..), LImportDecl, ForeignDecl(..), HsGroup(..), HsValBinds(..), Sig(..), collectHsBindLocatedBinders, tyClDeclNames, - instDeclATs, isIdxTyDecl, + instDeclATs, isFamInstDecl, LIE ) import RnEnv import RnHsDoc ( rnHsDoc ) import IfaceEnv ( ifaceExportNames ) -import LoadIface ( loadSrcInterface ) +import LoadIface ( loadSrcInterface, loadSysInterface ) import TcRnMonad hiding (LIE) import PrelNames import Module import Name -import NameSet import NameEnv -import OccName ( srcDataName, isTcOcc, pprNonVarNameSpace, - occNameSpace, - OccEnv, mkOccEnv, lookupOccEnv, emptyOccEnv, - extendOccEnv ) -import HscTypes ( GenAvailInfo(..), AvailInfo, availNames, availName, - HomePackageTable, PackageIfaceTable, - mkPrintUnqualified, availsToNameSet, - availsToNameEnv, - Deprecs(..), ModIface(..), Dependencies(..), - lookupIfaceByModule, ExternalPackageState(..) - ) -import RdrName ( RdrName, rdrNameOcc, setRdrNameSpace, - GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..), - emptyGlobalRdrEnv, plusGlobalRdrEnv, globalRdrEnvElts, - extendGlobalRdrEnv, lookupGlobalRdrEnv, unQualOK, lookupGRE_Name, - Provenance(..), ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..), - importSpecLoc, importSpecModule, isLocalGRE, pprNameProvenance ) +import NameSet +import OccName +import HscTypes +import RdrName import Outputable -import UniqFM 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 ( notNull ) -import Data.List ( nub, partition, concatMap ) +import Util +import ListSetOps +import Data.List ( partition, concatMap, (\\), delete ) import IO ( openFile, IOMode(..) ) import Monad ( when ) \end{code} @@ -72,7 +57,7 @@ import Monad ( when ) \begin{code} rnImports :: [LImportDecl RdrName] - -> RnM ([LImportDecl Name], GlobalRdrEnv, ImportAvails) + -> RnM ([LImportDecl Name], GlobalRdrEnv, ImportAvails,AnyHpcUsage) rnImports imports -- PROCESS IMPORT DECLS @@ -80,64 +65,62 @@ rnImports imports -- 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 + ifOptM Opt_WarnImplicitPrelude ( + when (notNull prel_imports) $ addWarn (implicitPreludeWarn) + ) + + stuff1 <- mapM (rnImportDecl this_mod) (prel_imports ++ ordinary) stuff2 <- mapM (rnImportDecl this_mod) source - let (decls, rdr_env, avails, imp_avails) = combine (stuff1 ++ stuff2) - return (decls, rdr_env, - imp_avails{ imp_parent = availsToNameEnv (nubAvails avails) }) - -- why wait until now to set the imp_parent, rather than - -- setting it in rnImportDecl for each import, and - -- combining them with plusImportAvails? The reason is - -- that we need to combine all the AvailInfos *before* - -- we build the NameEnv, otherwise the NameEnv can - -- end up with inconsistencies, eg. the parent can say - -- C(m1,m2), but the entry for m2 might only say C(m2). - -- The test mod118 illustrates the bug. + let (decls, rdr_env, imp_avails,hpc_usage) = combine (stuff1 ++ stuff2) + return (decls, rdr_env, imp_avails,hpc_usage) + where + combine :: [(LImportDecl Name, GlobalRdrEnv, ImportAvails,AnyHpcUsage)] + -> ([LImportDecl Name], GlobalRdrEnv, ImportAvails,AnyHpcUsage) + combine = foldr plus ([], emptyGlobalRdrEnv, emptyImportAvails,False) + where plus (decl, gbl_env1, imp_avails1,hpc_usage1) + (decls, gbl_env2, imp_avails2,hpc_usage2) + = (decl:decls, + gbl_env1 `plusGlobalRdrEnv` gbl_env2, + imp_avails1 `plusImportAvails` imp_avails2, + hpc_usage1 || hpc_usage2) + +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. - 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, +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 ] - combine :: [(LImportDecl Name, GlobalRdrEnv, [AvailInfo], ImportAvails)] - -> ([LImportDecl Name], GlobalRdrEnv, [AvailInfo], ImportAvails) - combine = foldr plus ([], emptyGlobalRdrEnv, [], emptyImportAvails) - where plus (decl, gbl_env1, avails1, imp_avails1) - (decls, gbl_env2, avails2, imp_avails2) - = (decl:decls, - gbl_env1 `plusGlobalRdrEnv` gbl_env2, - avails1 ++ avails2, - imp_avails1 `plusImportAvails` imp_avails2) - -preludeImportDecl :: LImportDecl RdrName -preludeImportDecl - = L loc $ - ImportDecl (L loc 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 - -> RnM (LImportDecl Name, GlobalRdrEnv, - [AvailInfo], ImportAvails) + -> RnM (LImportDecl Name, GlobalRdrEnv, ImportAvails,AnyHpcUsage) rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot qual_only as_mod imp_details)) @@ -165,7 +148,7 @@ rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot let imp_mod = mi_module iface deprecs = mi_deprecs iface - is_orph = mi_orphan iface + orph_iface = mi_orphan iface has_finsts = mi_finsts iface deps = mi_deps iface @@ -200,7 +183,7 @@ rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot total_avails <- ifaceExportNames filtered_exports -- filter the imports according to the import declaration - (new_imp_details, filtered_avails, gbl_env) <- + (new_imp_details, gbl_env) <- filterImports iface imp_spec imp_details total_avails dflags <- getDOpts @@ -208,9 +191,9 @@ rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot let -- Compute new transitive dependencies - orphans | is_orph = ASSERT( not (imp_mod `elem` dep_orphs deps) ) - imp_mod : dep_orphs deps - | otherwise = dep_orphs deps + orphans | orph_iface = ASSERT( not (imp_mod `elem` dep_orphs deps) ) + imp_mod : dep_orphs deps + | otherwise = dep_orphs deps finsts | has_finsts = ASSERT( not (imp_mod `elem` dep_finsts deps) ) imp_mod : dep_finsts deps @@ -246,17 +229,13 @@ rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot other -> False imports = ImportAvails { - imp_env = unitUFM qual_mod_name filtered_avails, imp_mods = unitModuleEnv imp_mod (imp_mod, import_all, loc), imp_orphs = orphans, imp_finsts = finsts, imp_dep_mods = mkModDeps dependent_mods, - imp_dep_pkgs = dependent_pkgs, - imp_parent = emptyNameEnv + imp_dep_pkgs = dependent_pkgs } - -- in - -- Complain if we import a deprecated module ifOptM Opt_WarnDeprecations ( case deprecs of @@ -267,7 +246,7 @@ rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot let new_imp_decl = L loc (ImportDecl loc_imp_mod_name want_boot qual_only as_mod new_imp_details) - returnM (new_imp_decl, gbl_env, filtered_avails, imports) + returnM (new_imp_decl, gbl_env, imports, mi_hpc iface) ) warnRedundantSourceImport mod_name @@ -296,64 +275,27 @@ importsFromLocalDecls group ; avails <- getLocalDeclBinders gbl_env group - ; implicit_prelude <- doptM Opt_ImplicitPrelude - ; let { - -- Optimisation: filter out names for built-in syntax - -- They just clutter up the environment (esp tuples), and the parser - -- will generate Exact RdrNames for them, so the cluttered - -- envt is no use. To avoid doing this filter all the time, - -- we use -fno-implicit-prelude as a clue that the filter is - -- worth while. Really, it's only useful for GHC.Base and GHC.Tuple. - -- - -- It's worth doing because it makes the environment smaller for - -- every module that imports the Prelude - -- - -- Note: don't filter the gbl_env (hence all_names, not filered_all_names - -- in defn of gres above). Stupid reason: when parsing - -- data type decls, the constructors start as Exact tycon-names, - -- and then get turned into data con names by zapping the name space; - -- but that stops them being Exact, so they get looked up. - -- Ditto in fixity decls; e.g. infix 5 : - -- Sigh. It doesn't matter because it only affects the Data.Tuple really. - -- The important thing is to trim down the exports. - names = concatMap availNames avails; - - filtered_avails - | implicit_prelude = avails - | otherwise = filterAvails (not.isBuiltInSyntax) avails; - - ; this_mod = tcg_mod gbl_env - ; imports = emptyImportAvails { - imp_env = unitUFM (moduleName this_mod) - filtered_avails, - imp_parent = availsToNameEnv avails - } - } - - ; rdr_env' <- extendRdrEnvRn (tcg_rdr_env gbl_env) names + ; rdr_env' <- extendRdrEnvRn (tcg_rdr_env gbl_env) avails ; traceRn (text "local avails: " <> ppr avails) - ; returnM (gbl_env { tcg_rdr_env = rdr_env', - tcg_imports = imports `plusImportAvails` tcg_imports gbl_env }) + ; returnM (gbl_env { tcg_rdr_env = rdr_env' }) } -extendRdrEnvRn :: GlobalRdrEnv -> [Name] -> RnM GlobalRdrEnv +extendRdrEnvRn :: GlobalRdrEnv -> [AvailInfo] -> RnM GlobalRdrEnv -- Add the new locally-bound names one by one, checking for duplicates as -- we do so. Remember that in Template Haskell the duplicates -- might *already be* in the GlobalRdrEnv from higher up the module -extendRdrEnvRn rdr_env names - = foldlM add_local rdr_env names +extendRdrEnvRn rdr_env avails + = foldlM add_local rdr_env (gresFromAvails LocalDef avails) where - add_local rdr_env name - | gres <- lookupGlobalRdrEnv rdr_env (nameOccName name) + add_local rdr_env gre + | gres <- lookupGlobalRdrEnv rdr_env (nameOccName (gre_name gre)) , (dup_gre:_) <- filter isLocalGRE gres -- Check for existing *local* defns - = do { addDupDeclErr (gre_name dup_gre) name + = do { addDupDeclErr (gre_name dup_gre) (gre_name gre) ; return rdr_env } | otherwise - = return (extendGlobalRdrEnv rdr_env new_gre) - where - new_gre = GRE {gre_name = name, gre_prov = LocalDef} + = return (extendGlobalRdrEnv rdr_env gre) \end{code} @getLocalDeclBinders@ returns the names for an @HsDecl@. It's @@ -361,7 +303,7 @@ used for source code. *** See "THE NAMING STORY" in HsDecls **** -Instances of indexed types +Instances of type families ~~~~~~~~~~~~~~~~~~~~~~~~~~ Indexed data/newtype instances contain data constructors that we need to collect, too. Moreover, we need to descend into the data/newtypes instances @@ -399,7 +341,7 @@ getLocalDeclBinders gbl_env (HsGroup {hs_valds = ValBindsIn val_decls val_sigs, for_hs_bndrs = [nm | L _ (ForeignImport nm _ _) <- foreign_decls] new_tc tc_decl - | isIdxTyDecl (unLoc tc_decl) + | isFamInstDecl (unLoc tc_decl) = do { main_name <- lookupFamInstDeclBndr mod main_rdr ; sub_names <- mappM (newTopSrcBinder mod) sub_rdrs ; return (AvailTC main_name sub_names) } @@ -413,6 +355,8 @@ getLocalDeclBinders gbl_env (HsGroup {hs_valds = ValBindsIn val_decls val_sigs, inst_ats inst_decl = mappM new_tc (instDeclATs (unLoc inst_decl)) + +getLocalDeclBinders _ _ = panic "getLocalDeclBinders" -- ValBindsOut can't happen \end{code} @@ -431,68 +375,74 @@ filterImports :: ModIface -> Maybe (Bool, [LIE RdrName]) -- Import spec; True => hiding -> [AvailInfo] -- What's available -> RnM (Maybe (Bool, [LIE Name]), -- Import spec w/ Names - [AvailInfo], -- What's imported GlobalRdrEnv) -- Same again, but in GRE form filterImports iface decl_spec Nothing all_avails - = return (Nothing, all_avails, mkGenericRdrEnv decl_spec all_avails) + = return (Nothing, mkGlobalRdrEnv (gresFromAvails prov all_avails)) + where + prov = Imported [ImpSpec { is_decl = decl_spec, is_item = ImpAll }] + filterImports iface decl_spec (Just (want_hiding, import_items)) all_avails - = do - -- check for errors, convert RdrNames to Names - opt_indexedtypes <- doptM Opt_IndexedTypes - items1 <- mapM (lookup_lie opt_indexedtypes) import_items - - let -- build the AvailInfo corresponding to each import item. - items2 = [ (ie, filterAvailByIE (unLoc ie) av) - | (ie,av) <- concat items1 ] - - -- eliminate duplicates - avails = nubAvails (map snd items2) - - -- the new import spec, with Names instead of RdrNames - imp_spec_out = Just (want_hiding, map fst items2) - - case want_hiding of - True -> - let - keep n = not (n `elemNameSet` availsToNameSet avails) - pruned_avails = filterAvails keep all_avails - in do - traceRn (text "pruned_avails: " <> ppr pruned_avails) - return (imp_spec_out, pruned_avails, - mkGenericRdrEnv decl_spec pruned_avails) - - False -> - let - gres = concat [ mkGlobalRdrEltsFromIE decl_spec lie avail - | (lie, avail) <- items2 ] - in do - traceRn (text "imported avails: " <> ppr avails) - return (imp_spec_out, avails, mkGlobalRdrEnv gres) + = do -- check for errors, convert RdrNames to Names + opt_typeFamilies <- doptM Opt_TypeFamilies + items1 <- mapM (lookup_lie opt_typeFamilies) import_items + + let items2 :: [(LIE Name, AvailInfo)] + items2 = concat items1 + -- NB the AvailInfo may have duplicates, and several items + -- for the same parent; e.g N(x) and N(y) + + names = availsToNameSet (map snd items2) + keep n = not (n `elemNameSet` names) + pruned_avails = filterAvails keep all_avails + hiding_prov = Imported [ImpSpec { is_decl = decl_spec, is_item = ImpAll }] + + gres | want_hiding = gresFromAvails hiding_prov pruned_avails + | otherwise = concatMap (gresFromIE decl_spec) items2 + + 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) + lookup_lie opt_typeFamilies (L loc ieRdr) = do stuff <- setSrcSpan loc $ - case lookup_ie opt_indexedtypes ieRdr of + case lookup_ie opt_typeFamilies ieRdr of Failed err -> addErr err >> return [] Succeeded a -> return a checkDodgyImport stuff return [ (L loc ie, avail) | (ie,avail) <- stuff ] where - -- warn when importing T(..) if T was exported absgtractly + -- Warn when importing T(..) if T was exported abstractly checkDodgyImport stuff | IEThingAll n <- ieRdr, (_, AvailTC _ [one]):_ <- stuff = ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn n)) @@ -506,9 +456,12 @@ filterImports iface decl_spec (Just (want_hiding, import_items)) all_avails -- 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 + lookup_ie opt_typeFamilies ie = let bad_ie = Failed (badImportItemErr iface decl_spec ie) lookup_name rdrName = @@ -518,12 +471,18 @@ filterImports iface decl_spec (Just (want_hiding, import_items)) all_avails in case ie of IEVar n -> do - (name,avail) <- lookup_name n - return [(IEVar name, avail)] + (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 ) @@ -534,34 +493,42 @@ filterImports iface decl_spec (Just (want_hiding, import_items)) all_avails in case catMaybeErr [ tc_name, dc_name ] of [] -> bad_ie - names -> return [ (IEThingAbs n, av) | (n,av) <- names ] + names -> return [mkIEThingAbs name | name <- names] | otherwise - -> do (name,avail) <- lookup_name tc - return [(IEThingAbs name, avail)] - - 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, avail)] - _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 type families + when (not opt_typeFamilies && 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} @@ -576,22 +543,37 @@ catMaybeErr ms = [ a | Succeeded a <- ms ] -- | make a 'GlobalRdrEnv' where all the elements point to the same -- import declaration (useful for "hiding" imports, or imports with -- no details). -mkGenericRdrEnv decl_spec avails - = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] } - | name <- concatMap availNames avails ] - where - imp_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll } - - --- | filters an 'AvailInfo' by the given import/export spec. -filterAvailByIE :: IE Name -> AvailInfo -> AvailInfo -filterAvailByIE (IEVar n) a@(Avail _) = a -filterAvailByIE (IEVar n) a@(AvailTC tc subs) = AvailTC tc [n] -filterAvailByIE (IEThingAbs n) a@(AvailTC _ _) = AvailTC n [n] -filterAvailByIE (IEThingAll n) a@(AvailTC tc subs) = a -filterAvailByIE (IEThingWith n ns) a@(AvailTC tc subs) = - AvailTC tc (filter (`elem` (n:ns)) subs) -filterAvailByIE _ _ = panic "filterAvailByIE" +gresFromAvails :: Provenance -> [AvailInfo] -> [GlobalRdrElt] +gresFromAvails prov avails + = concatMap (gresFromAvail (const prov)) avails + +gresFromAvail :: (Name -> Provenance) -> AvailInfo -> [GlobalRdrElt] +gresFromAvail prov_fn avail + = [ GRE {gre_name = n, + gre_par = availParent n avail, + gre_prov = prov_fn n} + | n <- availNames avail ] + +greAvail :: GlobalRdrElt -> AvailInfo +greAvail gre = mkUnitAvail (gre_name gre) (gre_par gre) + +mkUnitAvail :: Name -> Parent -> AvailInfo +mkUnitAvail me (ParentIs p) = AvailTC p [me] +mkUnitAvail me NoParent | isTyConName me = AvailTC me [me] + | otherwise = Avail me + +plusAvail (Avail n1) (Avail n2) = Avail n1 +plusAvail (AvailTC n1 ns1) (AvailTC n2 ns2) = AvailTC n2 (ns1 `unionLists` ns2) +plusAvail a1 a2 = pprPanic "RnEnv.plusAvail" (hsep [ppr a1,ppr a2]) + +availParent :: Name -> AvailInfo -> Parent +availParent n (Avail _) = NoParent +availParent n (AvailTC m ms) | n==m = NoParent + | otherwise = ParentIs m + +trimAvail :: AvailInfo -> Name -> AvailInfo +trimAvail (Avail n) m = Avail n +trimAvail (AvailTC n ns) m = ASSERT( m `elem` ns) AvailTC n [m] -- | filters 'AvailInfo's by the given predicate filterAvails :: (Name -> Bool) -> [AvailInfo] -> [AvailInfo] @@ -607,38 +589,73 @@ filterAvail keep ie rest = let left = filter keep ns in if null left then rest else AvailTC tc left : rest --- | combines 'AvailInfo's from the same family -nubAvails :: [AvailInfo] -> [AvailInfo] -nubAvails avails = nameEnvElts (foldr add emptyNameEnv avails) - where - add avail env = extendNameEnv_C comb_avails env (availName avail) avail - comb_avails (AvailTC tc subs1) (AvailTC _ subs2) - = AvailTC tc (nub (subs1 ++ subs2)) - comb_avails avail _ = avail - -- | Given an import/export spec, construct the appropriate 'GlobalRdrElt's. -mkGlobalRdrEltsFromIE :: ImpDeclSpec -> LIE Name -> AvailInfo -> [GlobalRdrElt] -mkGlobalRdrEltsFromIE decl_spec (L loc ie) avail = - case ie of - IEVar name -> - [mk_explicit_gre name] - IEThingAbs name -> - [mk_explicit_gre name] - IEThingAll name | AvailTC _ subs <- avail -> - mk_explicit_gre name : map mk_implicit_gre subs - IEThingWith name subs -> - mk_explicit_gre name : map mk_explicit_gre subs - _ -> - panic "mkGlobalRdrEltsFromIE" +gresFromIE :: ImpDeclSpec -> (LIE Name, AvailInfo) -> [GlobalRdrElt] +gresFromIE decl_spec (L loc ie, avail) + = gresFromAvail prov_fn avail where - mk_explicit_gre = mk_gre True - mk_implicit_gre = mk_gre False - - mk_gre explicit name = GRE { gre_name = name, - gre_prov = Imported [imp_spec] } - where - imp_spec = ImpSpec { is_decl = decl_spec, is_item = item_spec } - item_spec = ImpSome { is_explicit = explicit, is_iloc = loc } + is_explicit = case ie of + IEThingAll name -> \n -> n==name + other -> \n -> True + prov_fn name = Imported [imp_spec] + where + imp_spec = ImpSpec { is_decl = decl_spec, is_item = item_spec } + item_spec = ImpSome { is_explicit = is_explicit name, is_iloc = loc } + +mkChildEnv :: [GlobalRdrElt] -> NameEnv [Name] +mkChildEnv gres = foldr add emptyNameEnv gres + where + add (GRE { gre_name = n, gre_par = ParentIs p }) env = extendNameEnv_C (++) env p [n] + add other_gre env = env + +findChildren :: NameEnv [Name] -> Name -> [Name] +findChildren env n = lookupNameEnv env n `orElse` [] +\end{code} + +--------------------------------------- + AvailEnv and friends + +All this AvailEnv stuff is hardly used; only in a very small +part of RnNames. Todo: remove? +--------------------------------------- + +\begin{code} +type AvailEnv = NameEnv AvailInfo -- Maps a Name to the AvailInfo that contains it + +emptyAvailEnv :: AvailEnv +emptyAvailEnv = emptyNameEnv + +unitAvailEnv :: AvailInfo -> AvailEnv +unitAvailEnv a = unitNameEnv (availName a) a + +plusAvailEnv :: AvailEnv -> AvailEnv -> AvailEnv +plusAvailEnv = plusNameEnv_C plusAvail + +availEnvElts :: AvailEnv -> [AvailInfo] +availEnvElts = nameEnvElts + +addAvail :: AvailEnv -> AvailInfo -> AvailEnv +addAvail avails avail = extendNameEnv_C plusAvail avails (availName avail) avail + +mkAvailEnv :: [AvailInfo] -> AvailEnv + -- 'avails' may have several items with the same availName + -- E.g import Ix( Ix(..), index ) + -- will give Ix(Ix,index,range) and Ix(index) + -- 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 = map normaliseAvail . nameEnvElts . mkAvailEnv $ avails \end{code} @@ -663,9 +680,11 @@ it re-exports @GHC@, which includes @takeMVar#@, whose type includes \begin{code} type ExportAccum -- The type of the accumulating parameter of -- the main worker function in rnExports - = ([LIE Name], -- export items with Names + = ([LIE Name], -- Export items with Names ExportOccMap, -- Tracks exported occurrence names [AvailInfo]) -- The accumulated exported stuff + -- Not nub'd! + emptyExportAccum = ([], emptyOccEnv, []) type ExportOccMap = OccEnv (Name, IE RdrName) @@ -674,42 +693,44 @@ type ExportOccMap = OccEnv (Name, IE RdrName) -- it came from. It's illegal to export two distinct things -- that have the same occurrence name -rnExports :: Bool -- False => no 'module M(..) where' header at all +rnExports :: Bool -- False => no 'module M(..) where' header at all -> Maybe [LIE RdrName] -- Nothing => no explicit export list - -> RnM (Maybe [LIE Name], [AvailInfo]) + -> TcGblEnv + -> RnM TcGblEnv -- Complains if two distinct exports have same OccName -- Warns about identical exports. -- Complains about exports items not in scope -rnExports explicit_mod exports - = do TcGblEnv { tcg_mod = this_mod, - tcg_rdr_env = rdr_env, - tcg_imports = imports } <- getGblEnv - +rnExports explicit_mod exports + tcg_env@(TcGblEnv { tcg_mod = this_mod, + tcg_rdr_env = rdr_env, + tcg_imports = imports }) + = do { -- If the module header is omitted altogether, then behave -- as if the user had written "module Main(main) where..." -- EXCEPT in interactive mode, when we behave as if he had -- written "module Main where ..." -- Reason: don't want to complain about 'main' not in scope -- in interactive mode - ghc_mode <- getGhcMode - real_exports <- - case () of - () | explicit_mod - -> return exports - | ghc_mode == Interactive - -> return Nothing - | otherwise - -> do mainName <- lookupGlobalOccRn main_RDR_Unqual - return (Just ([noLoc (IEVar main_RDR_Unqual)])) - -- ToDo: the 'noLoc' here is unhelpful if 'main' turns - -- out to be out of scope - - (exp_spec, avails) <- exports_from_avail real_exports rdr_env - imports this_mod - return (exp_spec, nubAvails avails) - -- combine families + ; dflags <- getDOpts + ; let real_exports + | explicit_mod = exports + | ghcLink dflags == LinkInMemory = Nothing + | otherwise = Just ([noLoc (IEVar main_RDR_Unqual)]) + -- ToDo: the 'noLoc' here is unhelpful if 'main' + -- turns out to be out of scope + + ; (rn_exports, avails) <- exports_from_avail real_exports rdr_env imports this_mod + ; let final_avails = nubAvails avails -- Combine families + + ; return (tcg_env { tcg_exports = final_avails, + tcg_rn_exports = case tcg_rn_exports tcg_env of + Nothing -> Nothing + Just _ -> rn_exports, + tcg_dus = tcg_dus tcg_env `plusDU` + usesOnly (availsToNameSet final_avails) }) } + exports_from_avail :: Maybe [LIE RdrName] -- Nothing => no explicit export list @@ -719,129 +740,122 @@ exports_from_avail :: Maybe [LIE RdrName] -> RnM (Maybe [LIE Name], [AvailInfo]) exports_from_avail Nothing rdr_env imports this_mod - = -- the same as (module M) where M is the current module name, + = -- The same as (module M) where M is the current module name, -- so that's how we handle it. let - names = [ gre_name gre | gre <- globalRdrEnvElts rdr_env, + avails = [ greAvail gre | gre <- globalRdrEnvElts rdr_env, isLocalGRE gre ] - avails = map (lookupNameEnv_NF (imp_parent imports)) names in return (Nothing, avails) exports_from_avail (Just rdr_items) rdr_env imports this_mod - = do traceRn (text "parent: " <> ppr (imp_parent imports)) - (ie_names, _, exports) <- foldlM do_litem emptyExportAccum rdr_items + = do (ie_names, _, exports) <- foldlM do_litem emptyExportAccum rdr_items + return (Just ie_names, exports) where do_litem :: ExportAccum -> LIE RdrName -> RnM ExportAccum do_litem acc lie = setSrcSpan (getLoc lie) (exports_from_item acc lie) + kids_env :: NameEnv [Name] -- Maps a parent to its in-scope children + kids_env = mkChildEnv (globalRdrEnvElts rdr_env) + exports_from_item :: ExportAccum -> LIE RdrName -> RnM ExportAccum exports_from_item acc@(ie_names, occs, exports) - (L loc ie@(IEModuleContents mod)) - | mod `elem` mods -- Duplicate export of M + (L loc ie@(IEModuleContents mod)) + | let earlier_mods = [ mod | (L _ (IEModuleContents mod)) <- ie_names ] + , mod `elem` earlier_mods -- Duplicate export of M = do { warn_dup_exports <- doptM Opt_WarnDuplicateExports ; warnIf warn_dup_exports (dupModuleExport mod) ; returnM acc } | otherwise - = case lookupUFM (imp_env imports) mod of - Nothing -> do addErr (modExportErr mod) - return acc - Just avails - -> do traceRn (text "mod avails: " <> ppr mod <+> ppr avails) - let avails' = filterAvails (inScopeUnqual rdr_env) $ - nubAvails avails - new_exps = concatMap availNames avails' - - occs' <- check_occs ie occs new_exps + = do { implicit_prelude <- doptM Opt_ImplicitPrelude + ; let gres = filter (isModuleExported implicit_prelude mod) + (globalRdrEnvElts rdr_env) + + ; warnIf (null gres) (nullModuleExport mod) + + ; occs' <- check_occs ie occs (map gre_name gres) -- 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. - return (L loc (IEModuleContents mod) : ie_names, - occs', avails' ++ exports) - where - mods = [ mod | (L _ (IEModuleContents mod)) <- ie_names ] + ; return (L loc (IEModuleContents mod) : ie_names, + occs', map greAvail gres ++ exports) } exports_from_item acc@(lie_names, occs, exports) (L loc ie) - = do new_ie <- lookup_ie ie - let ie_name = ieName new_ie - if isUnboundName ie_name + | isDoc ie + = do new_ie <- lookup_doc_ie ie + return (L loc new_ie : lie_names, occs, exports) + + | otherwise + = do (new_ie, avail) <- lookup_ie ie + if isUnboundName (ieName new_ie) then return acc -- Avoid error cascade else do - if isDoc new_ie -- deal with docs - then return (L loc new_ie : lie_names, occs, exports) - else do - traceRn (text "lookup_avail: " <> ppr (lookup_avail ie_name)) - let avail = filterAvailByIE new_ie (lookup_avail ie_name) - new_exports = case new_ie of - IEThingWith n ns -> n : ns - _ -> availNames avail - -- ^^^ an IEThingWith might contain duplicates - -- whereas the avail doesn't, but we want - -- duplicates to be noticed by check_occs below. - -- checkErr (not (null (drop 1 new_exports))) (exportItemErr ie) - checkForDodgyExport new_ie new_exports - occs' <- check_occs ie occs new_exports - return (L loc new_ie : lie_names, occs', avail : exports) - - lookup_avail :: Name -> AvailInfo - lookup_avail name = - case lookupNameEnv avail_env name of - Nothing -> pprPanic "rnExports:lookup_avail" (ppr name) - Just a -> a - where avail_env = imp_parent imports - lookup_ie :: IE RdrName -> RnM (IE Name) + occs' <- check_occs ie occs (availNames avail) + return (L loc new_ie : lie_names, occs', avail : exports) + + ------------- + lookup_ie :: IE RdrName -> RnM (IE Name, AvailInfo) lookup_ie (IEVar rdr) - = do name <- lookupGlobalOccRn rdr - return (IEVar name) + = do gre <- lookupGreRn rdr + return (IEVar (gre_name gre), greAvail gre) lookup_ie (IEThingAbs rdr) + = 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 - return (IEThingAbs name) - - lookup_ie (IEThingAll rdr) - = do name <- lookupGlobalOccRn rdr - return (IEThingAll name) + let kids = findChildren kids_env name + when (null kids) + (if (isTyConName name) then addWarn (dodgyExportWarn name) + -- This occurs when you export T(..), but + -- only import T abstractly, or T is a synonym. + else addErr (exportItemErr ie)) + + return (IEThingAll name, AvailTC name (name:kids)) lookup_ie ie@(IEThingWith rdr sub_rdrs) = do name <- lookupGlobalOccRn rdr if isUnboundName name - then return (IEThingWith name []) + then return (IEThingWith name [], AvailTC name [name]) else do - let avail = lookup_avail name - env = mkOccEnv [ (nameOccName s, s) - | AvailTC _ subnames <- [avail], - s <- subnames ] - let mb_names = map (lookupOccEnv env . rdrNameOcc) sub_rdrs + let env = mkOccEnv [ (nameOccName s, s) + | s <- findChildren kids_env name ] + mb_names = map (lookupOccEnv env . rdrNameOcc) sub_rdrs if any isNothing mb_names then do addErr (exportItemErr ie) - return (IEThingWith name []) + return (IEThingWith name [], AvailTC name [name]) else do let names = catMaybes mb_names - optIdxTypes <- doptM Opt_IndexedTypes - when (not optIdxTypes && any isTyConName names) $ + optTyFam <- doptM Opt_TypeFamilies + when (not optTyFam && any isTyConName names) $ addErr (typeItemErr ( head . filter isTyConName $ names ) (text "in export list")) - return (IEThingWith name (catMaybes mb_names)) + return (IEThingWith name names, AvailTC name (name:names)) - lookup_ie (IEGroup lev doc) - = do rn_doc <- rnHsDoc doc - return (IEGroup lev rn_doc) - lookup_ie (IEDoc doc) - = do rn_doc <- rnHsDoc doc - return (IEDoc rn_doc) - lookup_ie (IEDocNamed str) - = return (IEDocNamed str) + lookup_ie ie = panic "lookup_ie" -- Other cases covered earlier - lookup_ie (IEModuleContents _) - = panic "rnExports:lookup_ie" -- caught earlier + ------------- + lookup_doc_ie :: IE RdrName -> RnM (IE Name) + lookup_doc_ie (IEGroup lev doc) = do rn_doc <- rnHsDoc doc + return (IEGroup lev rn_doc) + lookup_doc_ie (IEDoc doc) = do rn_doc <- rnHsDoc doc + return (IEDoc rn_doc) + lookup_doc_ie (IEDocNamed str) = return (IEDocNamed str) + lookup_doc_ie ie = panic "lookup_doc_ie" -- Other cases covered earlier isDoc (IEDoc _) = True @@ -850,21 +864,23 @@ isDoc (IEGroup _ _) = True isDoc _ = False ------------------------------- -inScopeUnqual :: GlobalRdrEnv -> Name -> Bool --- Checks whether the Name is in scope unqualified, --- regardless of whether it's ambiguous or not -inScopeUnqual env n = any unQualOK (lookupGRE_Name env n) - -------------------------------- -checkForDodgyExport :: IE Name -> [Name] -> RnM () -checkForDodgyExport ie@(IEThingAll tc) [n] - | isTcOcc (nameOccName n) = addWarn (dodgyExportWarn tc) - -- This occurs when you export T(..), but - -- only import T abstractly, or T is a synonym. - -- The single [n] is the type or class itself - | otherwise = addErr (exportItemErr ie) - -- This happes if you export x(..), which is bogus -checkForDodgyExport _ _ = return () +isModuleExported :: Bool -> ModuleName -> GlobalRdrElt -> Bool +-- True if the thing is in scope *both* unqualified, *and* with qualifier M +isModuleExported implicit_prelude mod (GRE { gre_name = name, gre_prov = prov }) + | implicit_prelude && isBuiltInSyntax name = False + -- Optimisation: filter out names for built-in syntax + -- They just clutter up the environment (esp tuples), and the parser + -- will generate Exact RdrNames for them, so the cluttered + -- envt is no use. To avoid doing this filter all the time, + -- we use -fno-implicit-prelude as a clue that the filter is + -- worth while. Really, it's only useful for GHC.Base and GHC.Tuple. + -- + -- It's worth doing because it makes the environment smaller for + -- every module that imports the Prelude + | otherwise + = case prov of + LocalDef -> moduleName (nameModule name) == mod + Imported is -> any unQualSpecOK is && any (qualSpecOK mod) is ------------------------------- check_occs :: IE RdrName -> ExportOccMap -> [Name] -> RnM ExportOccMap @@ -896,23 +912,31 @@ check_occs ie occs names %********************************************************* \begin{code} -reportDeprecations :: DynFlags -> TcGblEnv -> RnM () -reportDeprecations dflags tcg_env - = ifOptM Opt_WarnDeprecations $ - do { (eps,hpt) <- getEpsAndHpt +finishDeprecations :: DynFlags -> Maybe DeprecTxt + -> TcGblEnv -> RnM TcGblEnv +-- (a) Report usasge of deprecated imports +-- (b) If the whole module is deprecated, update tcg_deprecs +-- All this happens only once per module +finishDeprecations dflags mod_deprec tcg_env + = do { (eps,hpt) <- getEpsAndHpt + ; ifOptM Opt_WarnDeprecations $ + mapM_ (check hpt (eps_PIT eps)) all_gres -- By this time, typechecking is complete, -- so the PIT is fully populated - ; mapM_ (check hpt (eps_PIT eps)) all_gres } + + -- Deal with a module deprecation; it overrides all existing deprecs + ; let new_deprecs = case mod_deprec of + Just txt -> DeprecAll txt + Nothing -> tcg_deprecs tcg_env + ; return (tcg_env { tcg_deprecs = new_deprecs }) } where used_names = allUses (tcg_dus tcg_env) -- Report on all deprecated uses; hence allUses all_gres = globalRdrEnvElts (tcg_rdr_env tcg_env) - avail_env = imp_parent (tcg_imports tcg_env) - - check hpt pit (GRE {gre_name = name, gre_prov = Imported (imp_spec:_)}) + check hpt pit gre@(GRE {gre_name = name, gre_prov = Imported (imp_spec:_)}) | name `elemNameSet` used_names - , Just deprec_txt <- lookupDeprec dflags hpt pit avail_env name + , Just deprec_txt <- lookupImpDeprec dflags hpt pit gre = addWarnAt (importSpecLoc imp_spec) (sep [ptext SLIT("Deprecated use of") <+> pprNonVarNameSpace (occNameSpace (nameOccName name)) <+> @@ -934,30 +958,43 @@ reportDeprecations dflags tcg_env -- the defn of a non-deprecated thing, when changing a module's -- interface -lookupDeprec :: DynFlags -> HomePackageTable -> PackageIfaceTable - -> NameEnv AvailInfo -- parent info - -> Name -> Maybe DeprecTxt -lookupDeprec dflags hpt pit avail_env n - = case lookupIfaceByModule dflags 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 +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 + ParentIs p -> mi_dep_fn iface p -- its parent*, is deprec'd + NoParent -> Nothing + + Nothing -> Nothing -- See Note [Used names with interface not loaded] where - nameParent n = case lookupNameEnv avail_env n of - Just (AvailTC parent _) -> parent - _ -> n - -gre_is_used :: NameSet -> GlobalRdrElt -> Bool -gre_is_used used_names gre = gre_name gre `elemNameSet` used_names + name = gre_name gre \end{code} +Note [Used names with interface not loaded] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +By now all the interfaces should have been loaded, +because reportDeprecations happens after typechecking. +However, it's still (just) possible to to find a used +Name whose interface hasn't been loaded: + +a) It might be a WiredInName; in that case we may not load + its interface (although we could). + +b) It might be GHC.Real.fromRational, or GHC.Num.fromInteger + These are seen as "used" by the renamer (if -fno-implicit-prelude) + is on), but the typechecker may discard their uses + if in fact the in-scope fromRational is GHC.Read.fromRational, + (see tcPat.tcOverloadedLit), and the typechecker sees that the type + is fixed, say, to GHC.Base.Float (see Inst.lookupSimpleInst). + In that obscure case it won't force the interface in. + +In both cases we simply don't permit deprecations; +this is, after all, wired-in stuff. + + %********************************************************* %* * Unused names @@ -975,32 +1012,32 @@ reportUnusedNames export_decls gbl_env ; warnDuplicateImports defined_and_used ; printMinimalImports minimal_imports } where - used_names, all_used_names :: NameSet + used_names :: NameSet used_names = findUses (tcg_dus gbl_env) emptyNameSet -- NB: currently, if f x = g, we only treat 'g' as used if 'f' is used -- Hence findUses - avail_env = imp_parent (tcg_imports gbl_env) - nameParent_maybe n = case lookupNameEnv avail_env n of - Just (AvailTC tc _) | tc /= n -> Just tc - _otherwise -> Nothing - - all_used_names = used_names `unionNameSets` - mkNameSet (mapCatMaybes nameParent_maybe (nameSetToList used_names)) - -- A use of C implies a use of T, - -- if C was brought into scope by T(..) or T(C) - -- Collect the defined names from the in-scope environment 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 + -- rather than just used_names defined_and_used, defined_but_not_used :: [GlobalRdrElt] (defined_and_used, defined_but_not_used) - = partition (gre_is_used all_used_names) defined_names + = partition (gre_is_used used_names) defined_names + kids_env = mkChildEnv defined_names + -- This is done in mkExports too; duplicated work + + gre_is_used :: NameSet -> GlobalRdrElt -> Bool + gre_is_used used_names (GRE {gre_name = name}) + = name `elemNameSet` used_names + || any (`elemNameSet` used_names) (findChildren kids_env name) + -- A use of C implies a use of T, + -- if C was brought into scope by T(..) or T(C) + -- Filter out the ones that are -- (a) defined in this module, and -- (b) not defined by a 'deriving' clause @@ -1010,14 +1047,15 @@ reportUnusedNames export_decls gbl_env 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 @@ -1046,11 +1084,10 @@ reportUnusedNames export_decls gbl_env -- 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 - = addToFM_C plusAvailEnv acc (importSpecModule (head imp_specs)) - (unitAvailEnv (mk_avail n (nameParent_maybe n))) - add_name other acc - = acc + add_name gre@(GRE {gre_prov = Imported (imp_spec:_)}) acc + = addToFM_C plusAvailEnv acc + (importSpecModule imp_spec) (unitAvailEnv (greAvail gre)) + add_name gre acc = acc -- Local -- Modules mentioned as 'module M' in the export list expall_mods = case export_decls of @@ -1073,11 +1110,6 @@ reportUnusedNames export_decls gbl_env -- qualified imports into account. But it's an improvement. add_expall mod acc = addToFM_C plusAvailEnv acc mod emptyAvailEnv - -- n is the name of the thing, p is the name of its parent - mk_avail n (Just p) = AvailTC p [p,n] - mk_avail n Nothing | isTcOcc (nameOccName n) = AvailTC n [n] - | otherwise = Avail n - add_inst_mod (mod,_,_) acc | mod_name `elemFM` acc = acc -- We import something already | otherwise = addToFM acc mod_name emptyAvailEnv @@ -1099,6 +1131,7 @@ reportUnusedNames export_decls gbl_env -- -- 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), @@ -1111,6 +1144,12 @@ reportUnusedNames export_decls gbl_env 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 @@ -1129,8 +1168,6 @@ warnDuplicateImports :: [GlobalRdrElt] -> RnM () 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 @@ -1149,7 +1186,12 @@ warnDuplicateImports gres 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 @@ -1170,6 +1212,10 @@ warnDuplicateImports gres = 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 @@ -1177,16 +1223,11 @@ warnDuplicateImports gres = 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 @@ -1194,7 +1235,7 @@ printMinimalImports :: FiniteMap ModuleName AvailEnv -- Minimal imports printMinimalImports imps = ifOptM Opt_D_dump_minimal_imports $ do { - mod_ies <- mappM to_ies (fmToList imps) ; + mod_ies <- initIfaceTcRn $ mappM to_ies (fmToList imps) ; this_mod <- getModule ; rdr_env <- getGlobalRdrEnv ; ioToTcRn (do { h <- openFile (mkFilename this_mod) WriteMode ; @@ -1215,7 +1256,7 @@ printMinimalImports imps to_ies (mod, avail_env) = do ies <- mapM to_ie (availEnvElts avail_env) returnM (mod, ies) - to_ie :: AvailInfo -> RnM (IE Name) + to_ie :: AvailInfo -> IfG (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. @@ -1223,9 +1264,9 @@ printMinimalImports imps to_ie (AvailTC n [m]) = ASSERT( n==m ) returnM (IEThingAbs n) to_ie (AvailTC n ns) - = loadSrcInterface doc n_mod False `thenM` \ iface -> + = loadSysInterface doc n_mod `thenM` \ iface -> case [xs | (m,as) <- mi_exports iface, - moduleName m == n_mod, + m == n_mod, AvailTC x xs <- as, x == nameOccName n] of [xs] | all_used xs -> returnM (IEThingAll n) @@ -1235,7 +1276,7 @@ printMinimalImports imps where all_used avail_occs = all (`elem` map nameOccName ns) avail_occs doc = text "Compute minimal imports from" <+> ppr n - n_mod = moduleName (nameModule n) + n_mod = nameModule n \end{code} @@ -1260,24 +1301,23 @@ dodgyExportWarn item = dodgyMsg (ptext SLIT("export")) item dodgyMsg kind tc = sep [ ptext SLIT("The") <+> kind <+> ptext SLIT("item") <+> quotes (ppr (IEThingAll tc)), - ptext SLIT("suggests that") <+> quotes (ppr tc) <+> ptext SLIT("has constructor or class methods"), - ptext SLIT("but it has none; it is a type synonym or abstract type or class") ] + ptext SLIT("suggests that") <+> quotes (ppr tc) <+> ptext SLIT("has constructors or class methods,"), + ptext SLIT("but it has none") ] -modExportErr mod - = hsep [ ptext SLIT("Unknown module in export list: module"), quotes (ppr mod)] - exportItemErr export_item = sep [ ptext SLIT("The export item") <+> quotes (ppr export_item), ptext SLIT("attempts to export constructors or class methods that are not visible here") ] typeItemErr name wherestr = sep [ ptext SLIT("Using 'type' tag on") <+> quotes (ppr name) <+> wherestr, - ptext SLIT("Use -findexed-types to enable this extension") ] + ptext SLIT("Use -ftype-families to enable this extension") ] +exportClashErr :: GlobalRdrEnv -> Name -> Name -> IE RdrName -> IE RdrName + -> Message exportClashErr global_env name1 name2 ie1 ie2 = vcat [ ptext SLIT("Conflicting exports for") <+> quotes (ppr occ) <> colon - , ppr_export ie1 name1 - , ppr_export ie2 name2 ] + , ppr_export ie1' name1' + , ppr_export ie2' name2' ] where occ = nameOccName name1 ppr_export ie name = nest 2 (quotes (ppr ie) <+> ptext SLIT("exports") <+> @@ -1288,6 +1328,10 @@ exportClashErr global_env name1 name2 ie1 ie2 = case lookupGRE_Name global_env name of (gre:_) -> gre [] -> pprPanic "exportClashErr" (ppr name) + get_loc name = nameSrcLoc $ gre_name $ get_gre name + (name1', ie1', name2', ie2') = if get_loc name1 < get_loc name2 + then (name1, ie1, name2, ie2) + else (name2, ie2, name1, ie1) addDupDeclErr :: Name -> Name -> TcRn () addDupDeclErr name_a name_b @@ -1310,7 +1354,13 @@ dupModuleExport mod quotes (ptext SLIT("Module") <+> ppr mod), ptext SLIT("in export list")] +nullModuleExport mod + = ptext SLIT("The export item `module") <+> ppr mod <> ptext SLIT("' exports nothing") + moduleDeprec mod txt = sep [ ptext SLIT("Module") <+> quotes (ppr mod) <+> ptext SLIT("is deprecated:"), nest 4 (ppr txt) ] + +implicitPreludeWarn + = ptext SLIT("Module `Prelude' implicitly imported") \end{code}