X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Frename%2FRnNames.lhs;h=90cf81fc5f86dc305bc0211e1bce816d2bc029d6;hb=9530e7922d07ac2272e26078c6c626a333d1a761;hp=31ab4c78c8267d6be722c30a7d64bf3bf27c85db;hpb=a357abfc2ed4f0ac6eae1cf542fe4fb3bebe686e;p=ghc-hetmet.git diff --git a/compiler/rename/RnNames.lhs b/compiler/rename/RnNames.lhs index 31ab4c7..90cf81f 100644 --- a/compiler/rename/RnNames.lhs +++ b/compiler/rename/RnNames.lhs @@ -5,8 +5,8 @@ \begin{code} module RnNames ( - rnImports, mkRdrEnvAndImports, importsFromLocalDecls, - rnExports, mkExportNameSet, + rnImports, importsFromLocalDecls, + rnExports, getLocalDeclBinders, extendRdrEnvRn, reportUnusedNames, reportDeprecations ) where @@ -20,45 +20,47 @@ import HsSyn ( IE(..), ieName, ImportDecl(..), LImportDecl, instDeclATs, isIdxTyDecl, LIE ) import RnEnv +import RnHsDoc ( rnHsDoc ) import IfaceEnv ( ifaceExportNames ) import LoadIface ( loadSrcInterface ) import TcRnMonad hiding (LIE) -import FiniteMap import PrelNames import Module -import Name ( Name, nameSrcLoc, nameOccName, nameModule, isWiredInName, - nameParent, nameParent_maybe, isExternalName, - isBuiltInSyntax ) -import NameSet +import Name import NameEnv -import OccName ( srcDataName, isTcOcc, pprNonVarNameSpace, +import NameSet +import OccName ( srcDataName, pprNonVarNameSpace, occNameSpace, - OccEnv, mkOccEnv, lookupOccEnv, emptyOccEnv, - extendOccEnv ) -import HscTypes ( GenAvailInfo(..), AvailInfo, + OccEnv, mkOccEnv, mkOccEnv_C, lookupOccEnv, + emptyOccEnv, extendOccEnv ) +import HscTypes ( GenAvailInfo(..), AvailInfo, availNames, availName, HomePackageTable, PackageIfaceTable, - mkPrintUnqualified, + mkPrintUnqualified, availsToNameSet, Deprecs(..), ModIface(..), Dependencies(..), lookupIfaceByModule, ExternalPackageState(..) ) -import RdrName ( RdrName, rdrNameOcc, setRdrNameSpace, +import RdrName ( RdrName, rdrNameOcc, setRdrNameSpace, Parent(..), GlobalRdrEnv, mkGlobalRdrEnv, GlobalRdrElt(..), emptyGlobalRdrEnv, plusGlobalRdrEnv, globalRdrEnvElts, - extendGlobalRdrEnv, lookupGlobalRdrEnv, unQualOK, lookupGRE_Name, + extendGlobalRdrEnv, lookupGlobalRdrEnv, + lookupGRE_RdrName, lookupGRE_Name, Provenance(..), ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..), - importSpecLoc, importSpecModule, isLocalGRE, pprNameProvenance ) + importSpecLoc, importSpecModule, isLocalGRE, pprNameProvenance, + unQualSpecOK, qualSpecOK ) import Outputable -import UniqFM -import Maybes ( isNothing, catMaybes, mapCatMaybes, seqMaybe, orElse ) -import SrcLoc ( Located(..), mkGeneralSrcSpan, +import Maybes +import SrcLoc ( Located(..), mkGeneralSrcSpan, getLoc, unLoc, noLoc, srcLocSpan, SrcSpan ) +import FiniteMap +import ErrUtils import BasicTypes ( DeprecTxt ) import DriverPhases ( isHsBoot ) -import Util ( notNull ) -import List ( partition ) +import Util +import ListSetOps +import Data.List ( partition, concatMap, (\\), delete ) import IO ( openFile, IOMode(..) ) -import Monad ( liftM ) +import Monad ( when ) \end{code} @@ -70,7 +72,9 @@ import Monad ( liftM ) %************************************************************************ \begin{code} -rnImports :: [LImportDecl RdrName] -> RnM [LImportDecl Name] +rnImports :: [LImportDecl RdrName] + -> RnM ([LImportDecl Name], GlobalRdrEnv, ImportAvails) + rnImports imports -- PROCESS IMPORT DECLS -- Do the non {- SOURCE -} ones first, so that we get a helpful @@ -80,11 +84,12 @@ rnImports imports let all_imports = mk_prel_imports this_mod implicit_prelude ++ imports (source, ordinary) = partition is_source_import all_imports is_source_import (L _ (ImportDecl _ is_boot _ _ _)) = is_boot - get_imports = rnImportDecl this_mod - stuff1 <- mapM get_imports ordinary - stuff2 <- mapM get_imports source - return (stuff1 ++ stuff2) + stuff1 <- mapM (rnImportDecl this_mod) 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 @@ -99,6 +104,15 @@ rnImports imports = notNull [ () | L _ (ImportDecl mod _ _ _ _) <- imports, unLoc mod == pRELUDE_NAME ] + combine :: [(LImportDecl Name, GlobalRdrEnv, ImportAvails)] + -> ([LImportDecl Name], GlobalRdrEnv, ImportAvails) + combine = foldr plus ([], emptyGlobalRdrEnv, emptyImportAvails) + where plus (decl, gbl_env1, imp_avails1) + (decls, gbl_env2, imp_avails2) + = (decl:decls, + gbl_env1 `plusGlobalRdrEnv` gbl_env2, + imp_avails1 `plusImportAvails` imp_avails2) + preludeImportDecl :: LImportDecl RdrName preludeImportDecl = L loc $ @@ -110,140 +124,51 @@ preludeImportDecl where loc = mkGeneralSrcSpan FSLIT("Implicit import declaration") -mkRdrEnvAndImports :: [LImportDecl Name] -> RnM (GlobalRdrEnv, ImportAvails) -mkRdrEnvAndImports imports - = do this_mod <- getModule - let get_imports = importsFromImportDecl this_mod - stuff <- mapM get_imports imports - let (imp_gbl_envs, imp_avails) = unzip stuff - gbl_env :: GlobalRdrEnv - gbl_env = foldr plusGlobalRdrEnv emptyGlobalRdrEnv imp_gbl_envs - - all_avails :: ImportAvails - all_avails = foldr plusImportAvails emptyImportAvails imp_avails - -- ALL DONE - return (gbl_env, all_avails) - -\end{code} -\begin{code} -rnImportDecl :: Module - -> LImportDecl RdrName - -> RnM (LImportDecl Name) -rnImportDecl this_mod (L loc importDecl@(ImportDecl loc_imp_mod_name want_boot qual_only as_mod imp_details)) - = setSrcSpan loc $ - do iface <- loadSrcInterface doc imp_mod_name want_boot - let qual_mod_name = case as_mod of - Nothing -> imp_mod_name - Just another_name -> another_name - imp_spec = ImpDeclSpec { is_mod = imp_mod_name, is_qual = qual_only, - is_dloc = loc, is_as = qual_mod_name } - total_avails <- ifaceExportNames (mi_exports iface) - importDecl' <- rnImportDecl' iface imp_spec importDecl total_avails - return (L loc importDecl') - where imp_mod_name = unLoc loc_imp_mod_name - doc = ppr imp_mod_name <+> ptext SLIT("is directly imported") - -rnImportDecl' :: ModIface -> ImpDeclSpec -> ImportDecl RdrName -> NameSet -> RnM (ImportDecl Name) -rnImportDecl' iface decl_spec (ImportDecl mod_name want_boot qual_only as_mod Nothing) all_names - = return $ ImportDecl mod_name want_boot qual_only as_mod Nothing -rnImportDecl' iface decl_spec (ImportDecl mod_name want_boot qual_only as_mod (Just (want_hiding,import_items))) all_names - = do import_items_mbs <- mapM (srcSpanWrapper) import_items - let rn_import_items = concat . catMaybes $ import_items_mbs - return $ ImportDecl mod_name want_boot qual_only as_mod (Just (want_hiding,rn_import_items)) - where - srcSpanWrapper (L span ieRdr) - = case get_item ieRdr of - Nothing - -> do addErrAt span (badImportItemErr iface decl_spec ieRdr) - return Nothing - Just ieNames - -> return (Just [L span ie | ie <- ieNames]) - occ_env :: OccEnv Name -- Maps OccName to corresponding Name - occ_env = mkOccEnv [(nameOccName n, n) | n <- nameSetToList all_names] - -- 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. - sub_env :: NameEnv [Name] - sub_env = mkSubNameEnv all_names - - get_item :: IE RdrName -> Maybe [IE Name] - -- Empty result for a bad item. - -- Singleton result is typical case. - -- Can have two when we are hiding, and mention C which might be - -- both a class and a data constructor. - get_item item@(IEModuleContents _) - = Nothing - get_item (IEThingAll tc) - = do name <- check_name tc - return [IEThingAll name] - get_item (IEThingAbs tc) - | want_hiding -- hiding ( C ) - -- Here the 'C' can be a data constructor - -- *or* a type/class, or even both - = case catMaybes [check_name tc, check_name (setRdrNameSpace tc srcDataName)] of - [] -> Nothing - names -> return [ IEThingAbs n | n <- names ] - | otherwise - = do name <- check_name tc - return [IEThingAbs name] - get_item (IEThingWith n ns) -- import (C (A,B)) - = do name <- check_name n - let env = mkOccEnv [(nameOccName s, s) | s <- subNames sub_env name] - mb_names = map (lookupOccEnv env . rdrNameOcc) ns - names <- sequence mb_names - return [IEThingWith name names] - get_item (IEVar n) - = do name <- check_name n - return [IEVar name] - - check_name :: RdrName -> Maybe Name - check_name rdrName - = lookupOccEnv occ_env (rdrNameOcc rdrName) - - -importsFromImportDecl :: Module - -> LImportDecl Name - -> RnM (GlobalRdrEnv, ImportAvails) - -importsFromImportDecl this_mod - (L loc (ImportDecl loc_imp_mod_name want_boot qual_only as_mod imp_details)) +rnImportDecl :: Module + -> LImportDecl RdrName + -> RnM (LImportDecl Name, GlobalRdrEnv, ImportAvails) + +rnImportDecl this_mod (L loc (ImportDecl loc_imp_mod_name want_boot + qual_only as_mod imp_details)) = - setSrcSpan loc $ + setSrcSpan loc $ do -- If there's an error in loadInterface, (e.g. interface -- file not found) we get lots of spurious errors from 'filterImports' let imp_mod_name = unLoc loc_imp_mod_name doc = ppr imp_mod_name <+> ptext SLIT("is directly imported") - in - loadSrcInterface doc imp_mod_name want_boot `thenM` \ iface -> + + iface <- loadSrcInterface doc imp_mod_name want_boot -- Compiler sanity check: if the import didn't say -- {-# SOURCE #-} we should not get a hi-boot file - WARN( not want_boot && mi_boot iface, ppr imp_mod_name ) + WARN( not want_boot && mi_boot iface, ppr imp_mod_name ) (do -- Issue a user warning for a redundant {- SOURCE -} import -- NB that we arrange to read all the ordinary imports before -- any of the {- SOURCE -} imports warnIf (want_boot && not (mi_boot iface)) - (warnRedundantSourceImport imp_mod_name) `thenM_` + (warnRedundantSourceImport imp_mod_name) let - imp_mod = mi_module iface - deprecs = mi_deprecs iface - is_orph = mi_orphan iface - deps = mi_deps iface + imp_mod = mi_module iface + deprecs = mi_deprecs iface + is_orph = mi_orphan iface + has_finsts = mi_finsts iface + deps = mi_deps iface filtered_exports = filter not_this_mod (mi_exports iface) not_this_mod (mod,_) = mod /= this_mod - -- If the module exports anything defined in this module, just ignore it. - -- Reason: otherwise it looks as if there are two local definition sites - -- for the thing, and an error gets reported. Easiest thing is just to - -- filter them out up front. This situation only arises if a module - -- imports itself, or another module that imported it. (Necessarily, - -- this invoves a loop.) + -- If the module exports anything defined in this module, just + -- ignore it. Reason: otherwise it looks as if there are two + -- local definition sites for the thing, and an error gets + -- reported. Easiest thing is just to filter them out up + -- front. This situation only arises if a module imports + -- itself, or another module that imported it. (Necessarily, + -- this invoves a loop.) -- -- Tiresome consequence: if you say -- module A where @@ -260,13 +185,16 @@ importsFromImportDecl this_mod Just another_name -> another_name imp_spec = ImpDeclSpec { is_mod = imp_mod_name, is_qual = qual_only, is_dloc = loc, is_as = qual_mod_name } - in - -- Get the total imports, and filter them according to the import list - ifaceExportNames filtered_exports `thenM` \ total_avails -> - filterImports iface imp_spec - imp_details total_avails `thenM` \ (avail_env, gbl_env) -> + -- in + + -- Get the total exports from this module + total_avails <- ifaceExportNames filtered_exports + + -- filter the imports according to the import declaration + (new_imp_details, gbl_env) <- + filterImports2 iface imp_spec imp_details total_avails - getDOpts `thenM` \ dflags -> + dflags <- getDOpts let -- Compute new transitive dependencies @@ -275,6 +203,10 @@ importsFromImportDecl this_mod 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 + | otherwise = dep_finsts deps + pkg = modulePackageId (mi_module iface) (dependent_mods, dependent_pkgs) @@ -304,26 +236,26 @@ importsFromImportDecl this_mod Just (is_hiding, ls) -> not is_hiding && null ls other -> False - -- unqual_avails is the Avails that are visible in *unqualified* form - -- We need to know this so we know what to export when we see - -- module M ( module P ) where ... - -- Then we must export whatever came from P unqualified. imports = ImportAvails { - imp_env = unitUFM qual_mod_name avail_env, 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_dep_pkgs = dependent_pkgs + } - in -- Complain if we import a deprecated module ifOptM Opt_WarnDeprecations ( case deprecs of DeprecAll txt -> addWarn (moduleDeprec imp_mod_name txt) other -> returnM () - ) `thenM_` + ) + + let new_imp_decl = L loc (ImportDecl loc_imp_mod_name want_boot + qual_only as_mod new_imp_details) - returnM (gbl_env, imports) + returnM (new_imp_decl, gbl_env, imports) + ) warnRedundantSourceImport mod_name = ptext SLIT("Unnecessary {-# SOURCE #-} in the import of module") @@ -349,61 +281,29 @@ importsFromLocalDecls :: HsGroup RdrName -> RnM TcGblEnv importsFromLocalDecls group = do { gbl_env <- getGblEnv - ; names <- 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. - filtered_names - | implicit_prelude = names - | otherwise = filter (not . isBuiltInSyntax) names ; - - ; this_mod = tcg_mod gbl_env - ; imports = emptyImportAvails { - imp_env = unitUFM (moduleName this_mod) $ - mkNameSet filtered_names - } - } - - ; rdr_env' <- extendRdrEnvRn (tcg_rdr_env gbl_env) names - - ; returnM (gbl_env { tcg_rdr_env = rdr_env', - tcg_imports = imports `plusImportAvails` tcg_imports gbl_env }) + ; avails <- getLocalDeclBinders gbl_env group + + ; rdr_env' <- extendRdrEnvRn (tcg_rdr_env gbl_env) avails + + ; traceRn (text "local avails: " <> ppr avails) + + ; 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 @@ -423,7 +323,7 @@ raising a duplicate declaration error. So, we make a new name for it, but don't return it in the 'AvailInfo'. \begin{code} -getLocalDeclBinders :: TcGblEnv -> HsGroup RdrName -> RnM [Name] +getLocalDeclBinders :: TcGblEnv -> HsGroup RdrName -> RnM [AvailInfo] getLocalDeclBinders gbl_env (HsGroup {hs_valds = ValBindsIn val_decls val_sigs, hs_tyclds = tycl_decls, hs_instds = inst_decls, @@ -431,7 +331,7 @@ getLocalDeclBinders gbl_env (HsGroup {hs_valds = ValBindsIn val_decls val_sigs, = do { tc_names_s <- mappM new_tc tycl_decls ; at_names_s <- mappM inst_ats inst_decls ; val_names <- mappM new_simple val_bndrs - ; return (foldr (++) val_names (tc_names_s ++ concat at_names_s)) } + ; return (val_names ++ tc_names_s ++ concat at_names_s) } where mod = tcg_mod gbl_env is_hs_boot = isHsBoot (tcg_src gbl_env) ; @@ -440,23 +340,31 @@ getLocalDeclBinders gbl_env (HsGroup {hs_valds = ValBindsIn val_decls val_sigs, -- In a hs-boot file, the value binders come from the -- *signatures*, and there should be no foreign binders - new_simple rdr_name = newTopSrcBinder mod Nothing rdr_name + new_simple rdr_name = do + nm <- newTopSrcBinder mod rdr_name + return (Avail nm) sig_hs_bndrs = [nm | L _ (TypeSig nm _) <- val_sigs] val_hs_bndrs = collectHsBindLocatedBinders val_decls for_hs_bndrs = [nm | L _ (ForeignImport nm _ _) <- foreign_decls] new_tc tc_decl - = do { main_name <- newTopSrcBinder mod Nothing main_rdr - ; sub_names <- mappM (newTopSrcBinder mod (Just main_name)) sub_rdrs - ; if isIdxTyDecl (unLoc tc_decl) -- index type definitions - then return ( sub_names) -- are usage occurences - else return (main_name : sub_names) } - where - (main_rdr : sub_rdrs) = tyClDeclNames (unLoc tc_decl) + | isIdxTyDecl (unLoc tc_decl) + = do { main_name <- lookupFamInstDeclBndr mod main_rdr + ; sub_names <- mappM (newTopSrcBinder mod) sub_rdrs + ; return (AvailTC main_name sub_names) } + -- main_name is not bound here! + | otherwise + = do { main_name <- newTopSrcBinder mod main_rdr + ; sub_names <- mappM (newTopSrcBinder mod) sub_rdrs + ; return (AvailTC main_name (main_name : sub_names)) } + where + (main_rdr : sub_rdrs) = tyClDeclNames (unLoc tc_decl) inst_ats inst_decl = mappM new_tc (instDeclATs (unLoc inst_decl)) + +getLocalDeclBinders _ _ = panic "getLocalDeclBinders" -- ValBindsOut can't happen \end{code} @@ -472,73 +380,418 @@ available, and filters it through the import spec (if any). \begin{code} filterImports :: ModIface -> ImpDeclSpec -- The span for the entire import decl - -> Maybe (Bool, [LIE Name]) -- Import spec; True => hiding - -> NameSet -- What's available - -> RnM (NameSet, -- What's imported (qualified or unqualified) + -> Maybe (Bool, [LIE RdrName]) -- Import spec; True => hiding + -> [AvailInfo] -- What's available + -> RnM (Maybe (Bool, [LIE Name]), -- Import spec w/ Names GlobalRdrEnv) -- Same again, but in GRE form - - -- Complains if import spec mentions things that the module doesn't export - -- Warns/informs if import spec contains duplicates. -mkGenericRdrEnv decl_spec names - = mkGlobalRdrEnv [ GRE { gre_name = name, gre_prov = Imported [imp_spec] } - | name <- nameSetToList names ] +filterImports iface decl_spec Nothing all_avails + = return (Nothing, mkGlobalRdrEnv (gresFromAvails prov all_avails)) where - imp_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll } - -filterImports iface decl_spec Nothing all_names - = return (all_names, mkGenericRdrEnv decl_spec all_names) - -filterImports iface decl_spec (Just (want_hiding, import_items)) all_names - = mapM (addLocM get_item) import_items >>= \gres_s -> - let gres = concat gres_s - specified_names = mkNameSet (map gre_name gres) - in if not want_hiding then - return (specified_names, mkGlobalRdrEnv gres) - else let keep n = not (n `elemNameSet` specified_names) - pruned_avails = filterNameSet keep all_names - in return (pruned_avails, mkGenericRdrEnv decl_spec pruned_avails) + 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 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 - sub_env :: NameEnv [Name] -- Classify each name by its parent - sub_env = mkSubNameEnv all_names + -- This environment is how we map names mentioned in the import + -- 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, -- 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) + = do + stuff <- setSrcSpan loc $ + case lookup_ie opt_indexedtypes 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 abstractly + checkDodgyImport stuff + | IEThingAll n <- ieRdr, (_, AvailTC _ [one]):_ <- stuff + = ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn n)) + -- NB. use the RdrName for reporting the warning + checkDodgyImport _ + = return () + + -- For each import item, we convert its RdrNames to Names, + -- and at the same time construct an AvailInfo corresponding + -- to what is actually imported by this item. + -- 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. 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) + + lookup_name rdrName = + case lookupOccEnv occ_env (rdrNameOcc rdrName) of + Nothing -> bad_ie + Just n -> return n + in + case ie of + IEVar n -> do + (name, avail, _) <- lookup_name n + return [(IEVar name, trimAvail avail name)] + + IEThingAll tc -> do + (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 ) + -- Here the 'C' can be a data constructor + -- *or* a type/class, or even both + -> let tc_name = lookup_name tc + dc_name = lookup_name (setRdrNameSpace tc srcDataName) + in + case catMaybeErr [ tc_name, dc_name ] of + [] -> bad_ie + names -> return [mkIEThingAbs name | name <- names] + | otherwise + -> 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. - succeed_with :: Bool -> [Name] -> RnM [GlobalRdrElt] - succeed_with all_explicit names - = do { loc <- getSrcSpanM - ; returnM (map (mk_gre loc) names) } where - mk_gre loc 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 } - explicit = all_explicit || isNothing (nameParent_maybe name) - - get_item :: IE Name -> RnM [GlobalRdrElt] - -- Empty result for a bad item. - -- Singleton result is typical case. - -- Can have two when we are hiding, and mention C which might be - -- both a class and a data constructor. - get_item item@(IEModuleContents _) - -- This case should be filtered out by 'rnImports'. - = panic "filterImports: IEModuleContents?" - - get_item (IEThingAll name) - = case subNames sub_env name of - [] -> -- This occurs when you import T(..), but - -- only export T abstractly. - do ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn name)) - succeed_with False [name] - names -> succeed_with False (name:names) - - get_item (IEThingAbs name) - = succeed_with True [name] - - get_item (IEThingWith name names) - = succeed_with True (name:names) - get_item (IEVar name) - = succeed_with True [name] + 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} + +\begin{code} +filterImports2 :: ModIface + -> ImpDeclSpec -- The span for the entire import decl + -> Maybe (Bool, [LIE RdrName]) -- Import spec; True => hiding + -> [AvailInfo] -- What's available + -> RnM (Maybe (Bool, [LIE Name]), -- Import spec w/ Names + GlobalRdrEnv) -- Same again, but in GRE form + +filterImports2 iface decl_spec Nothing all_avails + = return (Nothing, mkGlobalRdrEnv (gresFromAvails prov all_avails)) + where + prov = Imported [ImpSpec { is_decl = decl_spec, is_item = ImpAll }] + + +filterImports2 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 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). + -- + -- 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 ] + + lookup_lie :: Bool -> LIE RdrName -> TcRn [(LIE Name, AvailInfo)] + lookup_lie opt_indexedtypes (L loc ieRdr) + = do + stuff <- setSrcSpan loc $ + case lookup_ie opt_indexedtypes 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 abstractly + checkDodgyImport stuff + | IEThingAll n <- ieRdr, (_, AvailTC _ [one]):_ <- stuff + = ifOptM Opt_WarnDodgyImports (addWarn (dodgyImportWarn n)) + -- NB. use the RdrName for reporting the warning + checkDodgyImport _ + = return () + + -- For each import item, we convert its RdrNames to Names, + -- and at the same time construct an AvailInfo corresponding + -- to what is actually imported by this item. + -- 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. + lookup_ie :: Bool -> IE RdrName -> MaybeErr Message [(IE Name,AvailInfo)] + lookup_ie opt_indexedtypes ie + = let bad_ie = Failed (badImportItemErr iface decl_spec ie) + + lookup_name rdrName = + case lookupOccEnv occ_env (rdrNameOcc rdrName) of + Nothing -> bad_ie + Just n -> return n + in + case ie of + IEVar n -> do + (name,avail) <- lookup_name n + return [(IEVar name, trimAvail avail name)] + + IEThingAll tc -> do + (name,avail) <- lookup_name tc + return [(IEThingAll name, avail)] + + IEThingAbs tc + | want_hiding -- hiding ( C ) + -- Here the 'C' can be a data constructor + -- *or* a type/class, or even both + -> let tc_name = lookup_name tc + dc_name = lookup_name (setRdrNameSpace tc srcDataName) + in + case catMaybeErr [ tc_name, dc_name ] of + [] -> bad_ie + names -> return [ (IEThingAbs n, trimAvail av n) + | (n,av) <- 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 + + _other -> Failed illegalImportItemErr + -- could be IEModuleContents, IEGroup, IEDoc, IEDocNamed + -- all errors. +\end{code} + +%************************************************************************ +%* * + Import/Export Utils +%* * +%************************************************************************ + +\begin{code} +-- | make a 'GlobalRdrEnv' where all the elements point to the same +-- import declaration (useful for "hiding" imports, or imports with +-- no details). +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] +filterAvails keep avails = foldr (filterAvail keep) [] avails + +-- | filters an 'AvailInfo' by the given predicate +filterAvail :: (Name -> Bool) -> AvailInfo -> [AvailInfo] -> [AvailInfo] +filterAvail keep ie rest = + case ie of + Avail n | keep n -> ie : rest + | otherwise -> rest + AvailTC tc ns -> + let left = filter keep ns in + if null left then rest else AvailTC tc left : rest + +-- | Given an import/export spec, construct the appropriate 'GlobalRdrElt's. +gresFromIE :: ImpDeclSpec -> (LIE Name, AvailInfo) -> [GlobalRdrElt] +gresFromIE decl_spec (L loc ie, avail) + = gresFromAvail prov_fn avail + where + 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} @@ -563,10 +816,12 @@ 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 - = ([ModuleName], -- 'module M's seen so far + = ([LIE Name], -- Export items with Names ExportOccMap, -- Tracks exported occurrence names - NameSet) -- The accumulated exported stuff -emptyExportAccum = ([], emptyOccEnv, emptyNameSet) + [AvailInfo]) -- The accumulated exported stuff + -- Not nub'd! + +emptyExportAccum = ([], emptyOccEnv, []) type ExportOccMap = OccEnv (Name, IE RdrName) -- Tracks what a particular exported OccName @@ -574,47 +829,17 @@ type ExportOccMap = OccEnv (Name, IE RdrName) -- it came from. It's illegal to export two distinct things -- that have the same occurrence name -rnExports :: Maybe [LIE RdrName] - -> RnM (Maybe [LIE Name]) -rnExports Nothing = return Nothing -rnExports (Just exports) - = do TcGblEnv { tcg_imports = ImportAvails { imp_env = imp_env } } <- getGblEnv - let sub_env :: NameEnv [Name] -- Classify each name by its parent - sub_env = mkSubNameEnv (foldUFM unionNameSets emptyNameSet imp_env) - rnExport (IEVar rdrName) - = do name <- lookupGlobalOccRn rdrName - return (IEVar name) - rnExport (IEThingAbs rdrName) - = do name <- lookupGlobalOccRn rdrName - return (IEThingAbs name) - rnExport (IEThingAll rdrName) - = do name <- lookupGlobalOccRn rdrName - return (IEThingAll name) - rnExport ie@(IEThingWith rdrName rdrNames) - = do name <- lookupGlobalOccRn rdrName - if isUnboundName name - then return (IEThingWith name []) - else do - let env = mkOccEnv [(nameOccName s, s) | s <- subNames sub_env name] - mb_names = map (lookupOccEnv env . rdrNameOcc) rdrNames - if any isNothing mb_names - then do addErr (exportItemErr ie) - return (IEThingWith name []) - else return (IEThingWith name (catMaybes mb_names)) - rnExport (IEModuleContents mod) - = return (IEModuleContents mod) - rn_exports <- mapM (wrapLocM rnExport) exports - return (Just rn_exports) - -mkExportNameSet :: Bool -- False => no 'module M(..) where' header at all - -> Maybe ([LIE Name], [LIE RdrName]) -- Nothing => no explicit export list - -> RnM NameSet +rnExports :: Bool -- False => no 'module M(..) where' header at all + -> Maybe [LIE RdrName] -- Nothing => no explicit export list + -> RnM (Maybe [LIE Name], [AvailInfo]) + -- Complains if two distinct exports have same OccName -- Warns about identical exports. -- Complains about exports items not in scope -mkExportNameSet explicit_mod exports - = do TcGblEnv { tcg_rdr_env = rdr_env, +rnExports explicit_mod exports + = do TcGblEnv { tcg_mod = this_mod, + tcg_rdr_env = rdr_env, tcg_imports = imports } <- getGblEnv -- If the module header is omitted altogether, then behave @@ -624,108 +849,172 @@ mkExportNameSet explicit_mod exports -- 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 mainName)] - ,[noLoc (IEVar main_RDR_Unqual)])) - -- ToDo: the 'noLoc' here is unhelpful if 'main' turns out to be out of scope - exports_from_avail real_exports rdr_env imports - - -exports_from_avail Nothing rdr_env imports - = -- Export all locally-defined things - -- We do this by filtering the global RdrEnv, - -- keeping only things that are locally-defined - return (mkNameSet [ gre_name gre - | gre <- globalRdrEnvElts rdr_env, - isLocalGRE gre ]) - -exports_from_avail (Just (items,origItems)) rdr_env (ImportAvails { imp_env = imp_env }) - = do (_, _, exports) <- foldlM do_litem emptyExportAccum (zip items origItems) - return exports + 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 + +exports_from_avail :: Maybe [LIE RdrName] + -- Nothing => no explicit export list + -> GlobalRdrEnv + -> ImportAvails + -> Module + -> 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, + -- so that's how we handle it. + let + avails = [ greAvail gre | gre <- globalRdrEnvElts rdr_env, + isLocalGRE gre ] + in + return (Nothing, avails) + +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 - sub_env :: NameEnv [Name] -- Classify each name by its parent - sub_env = mkSubNameEnv (foldUFM unionNameSets emptyNameSet imp_env) + do_litem :: ExportAccum -> LIE RdrName -> RnM ExportAccum + do_litem acc lie = setSrcSpan (getLoc lie) (exports_from_item acc lie) - do_litem :: ExportAccum -> (LIE Name, LIE RdrName) -> RnM ExportAccum - do_litem acc (ieName, ieRdr) - = addLocM (exports_from_item acc (unLoc ieRdr)) ieName + kids_env :: NameEnv [Name] -- Maps a parent to its in-scope children + kids_env = mkChildEnv (globalRdrEnvElts rdr_env) - exports_from_item :: ExportAccum -> IE RdrName -> IE Name -> RnM ExportAccum - exports_from_item acc@(mods, occs, exports) ieRdr@(IEModuleContents mod) ie - | mod `elem` mods -- Duplicate export of M + exports_from_item :: ExportAccum -> LIE RdrName -> RnM ExportAccum + exports_from_item acc@(ie_names, occs, exports) + (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 mod of - Nothing -> do addErr (modExportErr mod) - return acc - Just names - -> do let new_exports = filterNameSet (inScopeUnqual rdr_env) names - -- 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. - occs' <- check_occs ieRdr occs (nameSetToList new_exports) - return (mod:mods, occs', exports `unionNameSets` new_exports) - - exports_from_item acc@(mods, occs, exports) ieRdr ie - = if isUnboundName (ieName ie) - then return acc -- Avoid error cascade - else let new_exports = filterAvail ie sub_env in - do -- checkErr (not (null (drop 1 new_exports))) (exportItemErr ie) - checkForDodgyExport ie new_exports - occs' <- check_occs ieRdr occs new_exports - return (mods, occs', addListToNameSet exports new_exports) - -------------------------------- -filterAvail :: IE Name -- Wanted - -> NameEnv [Name] -- Maps type/class names to their sub-names - -> [Name] - -filterAvail (IEVar n) subs = [n] -filterAvail (IEThingAbs n) subs = [n] -filterAvail (IEThingAll n) subs = n : subNames subs n -filterAvail (IEThingWith n ns) subs = n : ns -filterAvail (IEModuleContents _) _ = panic "filterAvail" - -subNames :: NameEnv [Name] -> Name -> [Name] -subNames env n = lookupNameEnv env n `orElse` [] - -mkSubNameEnv :: NameSet -> NameEnv [Name] --- Maps types and classes to their constructors/classops respectively --- This mapping just makes it easier to deal with A(..) export items -mkSubNameEnv names - = foldNameSet add_name emptyNameEnv names - where - add_name name env - | Just parent <- nameParent_maybe name - = extendNameEnv_C (\ns _ -> name:ns) env parent [name] - | otherwise = env + = 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', map greAvail gres ++ exports) } + + exports_from_item acc@(lie_names, occs, exports) (L loc ie) + | isDoc ie + = do new_ie <- lookup_doc_ie ie + return (L loc new_ie : lie_names, occs, exports) -------------------------------- -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) + | otherwise + = do (new_ie, avail) <- lookup_ie ie + if isUnboundName (ieName new_ie) + then return acc -- Avoid error cascade + else do + + 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 gre <- lookupGreRn rdr + return (IEVar (gre_name gre), greAvail gre) + + lookup_ie (IEThingAbs rdr) + = do name <- lookupGlobalOccRn rdr + case lookupGRE_RdrName rdr rdr_env of + [] -> panic "RnNames.lookup_ie" + elt:_ -> case gre_par elt 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 + 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 [], AvailTC name [name]) + else do + 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 [], AvailTC name [name]) + else do let names = catMaybes mb_names + optIdxTypes <- doptM Opt_IndexedTypes + when (not optIdxTypes && any isTyConName names) $ + addErr (typeItemErr ( head + . filter isTyConName + $ names ) + (text "in export list")) + return (IEThingWith name names, AvailTC name (name:names)) + + lookup_ie ie = panic "lookup_ie" -- Other cases covered 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 +isDoc (IEDocNamed _) = True +isDoc (IEGroup _ _) = True +isDoc _ = False ------------------------------- -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 @@ -769,9 +1058,9 @@ reportDeprecations dflags tcg_env -- Report on all deprecated uses; hence allUses all_gres = globalRdrEnvElts (tcg_rdr_env 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 name + , Just deprec_txt <- lookupDeprec dflags hpt pit gre = addWarnAt (importSpecLoc imp_spec) (sep [ptext SLIT("Deprecated use of") <+> pprNonVarNameSpace (occNameSpace (nameOccName name)) <+> @@ -794,22 +1083,23 @@ reportDeprecations dflags tcg_env -- interface lookupDeprec :: DynFlags -> HomePackageTable -> PackageIfaceTable - -> Name -> Maybe DeprecTxt -lookupDeprec dflags hpt pit 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 + -> GlobalRdrElt -> Maybe DeprecTxt +lookupDeprec 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 - | isWiredInName n -> Nothing + | isWiredInName name -> 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) + | otherwise -> pprPanic "lookupDeprec" (ppr name) -- By now all the interfaces should have been loaded - -gre_is_used :: NameSet -> GlobalRdrElt -> Bool -gre_is_used used_names gre = gre_name gre `elemNameSet` used_names + where + name = gre_name gre \end{code} %********************************************************* @@ -829,27 +1119,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 - 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 @@ -895,11 +1190,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 @@ -922,11 +1216,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 @@ -1102,6 +1391,8 @@ badImportItemErr iface decl_spec ie source_import | mi_boot iface = ptext SLIT("(hi-boot interface)") | otherwise = empty +illegalImportItemErr = ptext SLIT("Illegal import item") + dodgyImportWarn item = dodgyMsg (ptext SLIT("import")) item dodgyExportWarn item = dodgyMsg (ptext SLIT("export")) item @@ -1110,13 +1401,14 @@ dodgyMsg kind 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") ] -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") ] + exportClashErr global_env name1 name2 ie1 ie2 = vcat [ ptext SLIT("Conflicting exports for") <+> quotes (ppr occ) <> colon , ppr_export ie1 name1 @@ -1153,6 +1445,9 @@ 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) ]