X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Frename%2FRnNames.lhs;h=2b91305d9b29abd2a4296268b9074a6e498b1540;hb=a6eede3173cee960884e732f40b0998cf84ae015;hp=b0ec1905be6c7bf7d6ce8d45a3c25d6898a899fa;hpb=7b0181919416d8f04324575b7e17031ca692f5b0;p=ghc-hetmet.git diff --git a/ghc/compiler/rename/RnNames.lhs b/ghc/compiler/rename/RnNames.lhs index b0ec190..2b91305 100644 --- a/ghc/compiler/rename/RnNames.lhs +++ b/ghc/compiler/rename/RnNames.lhs @@ -1,298 +1,689 @@ % -% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996 +% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % \section[RnNames]{Extracting imported and top-level names in scope} \begin{code} -#include "HsVersions.h" - module RnNames ( - getGlobalNames, - GlobalNameInfo(..) + getGlobalNames ) where -import PreludeGlaST ( returnPrimIO, thenPrimIO, MutableVar(..) ) +#include "HsVersions.h" -import Ubiq +import CmdLineOpts ( opt_NoImplicitPrelude, opt_WarnDuplicateExports, + opt_SourceUnchanged + ) + +import HsSyn ( HsModule(..), ImportDecl(..), HsDecl(..), TyClDecl(..), + IE(..), ieName, + ForeignDecl(..), ForKind(..), isDynamic, + FixitySig(..), Sig(..), + collectTopBinders + ) +import RdrHsSyn ( RdrName(..), RdrNameIE, RdrNameImportDecl, + RdrNameHsModule, RdrNameHsDecl, + rdrNameOcc, ieOcc + ) +import RnIfaces ( getInterfaceExports, getDeclBinders, getImportedFixities, + recordSlurp, checkUpToDate, loadHomeInterface + ) +import BasicTypes ( IfaceFlavour(..) ) +import RnEnv +import RnMonad -import HsSyn -import RdrHsSyn -import RnHsSyn +import FiniteMap +import PrelMods +import UniqFM ( lookupUFM ) +import Bag ( bagToList ) +import Maybes ( maybeToBool ) +import Name +import SrcLoc ( SrcLoc ) +import NameSet ( elemNameSet, emptyNameSet ) +import Outputable +import Unique ( getUnique ) +import Util ( removeDups, equivClassesByUniq, sortLt ) +import List ( nubBy ) +\end{code} -import RnMonad -import RnIfaces ( IfaceCache(..), cacheInterface, ParsedIface ) -import RnUtils ( RnEnv(..), emptyRnEnv, extendGlobalRnEnv, qualNameErr, dupNamesErr ) - -import Bag ( emptyBag, unitBag, unionBags, unionManyBags, mapBag, listToBag, bagToList ) -import ErrUtils ( Error(..), Warning(..), addShortErrLocLine ) -import FiniteMap ( fmToList ) -import Name ( RdrName(..), Name, isQual, mkTopLevName, - mkImportedName, nameExportFlag, - getLocalName, getSrcLoc, pprNonOp - ) -import PrelInfo ( BuiltinNames(..), BuiltinKeys(..) ) -import PrelMods ( fromPrelude ) -import Pretty -import SrcLoc ( SrcLoc ) -import UniqSupply ( splitUniqSupply ) -import Util ( equivClasses, panic ) + + +%************************************************************************ +%* * +\subsection{Get global names} +%* * +%************************************************************************ + +\begin{code} +getGlobalNames :: RdrNameHsModule + -> RnMG (Maybe (ExportEnv, + RnEnv, + NameEnv AvailInfo -- Maps a name to its parent AvailInfo + -- Just for in-scope things only + )) + -- Nothing => no need to recompile + +getGlobalNames (HsModule this_mod _ exports imports decls mod_loc) + = -- These two fix-loops are to get the right + -- provenance information into a Name + fixRn (\ ~(rec_exp_fn, _) -> + + fixRn (\ ~(rec_rn_env, _) -> + let + rec_unqual_fn :: Name -> Bool -- Is this chap in scope unqualified? + rec_unqual_fn = mkPrintUnqualFn rec_rn_env + in + -- PROCESS LOCAL DECLS + -- Do these *first* so that the correct provenance gets + -- into the global name cache. + importsFromLocalDecls this_mod rec_exp_fn decls `thenRn` \ (local_gbl_env, local_mod_avails) -> + + -- PROCESS IMPORT DECLS + mapAndUnzipRn (importsFromImportDecl this_mod rec_unqual_fn) + all_imports `thenRn` \ (imp_gbl_envs, imp_avails_s) -> + + -- COMBINE RESULTS + -- We put the local env second, so that a local provenance + -- "wins", even if a module imports itself. + let + gbl_env :: GlobalRdrEnv + imp_gbl_env = foldr plusGlobalRdrEnv emptyRdrEnv imp_gbl_envs + gbl_env = imp_gbl_env `plusGlobalRdrEnv` local_gbl_env + + export_avails :: ExportAvails + export_avails = foldr plusExportAvails local_mod_avails imp_avails_s + in + returnRn (gbl_env, export_avails) + ) `thenRn` \ (gbl_env, export_avails) -> + + -- TRY FOR EARLY EXIT + -- We can't go for an early exit before this because we have to check + -- for name clashes. Consider: + -- + -- module A where module B where + -- import B h = True + -- f = h + -- + -- Suppose I've compiled everything up, and then I add a + -- new definition to module B, that defines "f". + -- + -- Then I must detect the name clash in A before going for an early + -- exit. The early-exit code checks what's actually needed from B + -- to compile A, and of course that doesn't include B.f. That's + -- why we wait till after the plusRnEnv stuff to do the early-exit. + checkEarlyExit this_mod `thenRn` \ up_to_date -> + if up_to_date then + returnRn (junk_exp_fn, Nothing) + else + + -- FIXITIES + fixitiesFromLocalDecls gbl_env decls `thenRn` \ local_fixity_env -> + getImportedFixities `thenRn` \ imp_fixity_env -> + let + fixity_env = imp_fixity_env `plusNameEnv` local_fixity_env + rn_env = RnEnv gbl_env fixity_env + (_, global_avail_env) = export_avails + in + traceRn (text "fixity env" <+> vcat (map ppr (nameEnvElts fixity_env))) `thenRn_` + + -- PROCESS EXPORT LISTS + exportsFromAvail this_mod exports export_avails rn_env `thenRn` \ (export_fn, export_env) -> + + -- DONE + returnRn (export_fn, Just (export_env, rn_env, global_avail_env)) + ) `thenRn` \ (_, result) -> + returnRn result + where + junk_exp_fn = error "RnNames:export_fn" + + all_imports = prel_imports ++ imports + + -- 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. + prel_imports | this_mod == pRELUDE || + explicit_prelude_import || + opt_NoImplicitPrelude + = [] + + | otherwise = [ImportDecl pRELUDE + False {- Not qualified -} + HiFile {- Not source imported -} + Nothing {- No "as" -} + Nothing {- No import list -} + mod_loc] + + explicit_prelude_import + = not (null [ () | (ImportDecl mod qual _ _ _ _) <- imports, mod == pRELUDE ]) +\end{code} + +\begin{code} +checkEarlyExit mod + = checkErrsRn `thenRn` \ no_errs_so_far -> + if not no_errs_so_far then + -- Found errors already, so exit now + returnRn True + else + + traceRn (text "Considering whether compilation is required...") `thenRn_` + if not opt_SourceUnchanged then + -- Source code changed and no errors yet... carry on + traceRn (nest 4 (text "source file changed or recompilation check turned off")) `thenRn_` + returnRn False + else + + -- Unchanged source, and no errors yet; see if usage info + -- up to date, and exit if so + checkUpToDate mod `thenRn` \ up_to_date -> + putDocRn (text "Compilation" <+> + text (if up_to_date then "IS NOT" else "IS") <+> + text "required") `thenRn_` + returnRn up_to_date +\end{code} + +\begin{code} +importsFromImportDecl :: Module -- The module being compiled + -> (Name -> Bool) -- True => print unqualified + -> RdrNameImportDecl + -> RnMG (GlobalRdrEnv, + ExportAvails) + +importsFromImportDecl this_mod rec_unqual_fn (ImportDecl imp_mod qual_only as_source as_mod import_spec iloc) + = pushSrcLocRn iloc $ + getInterfaceExports imp_mod as_source `thenRn` \ avails -> + + if null avails then + -- If there's an error in getInterfaceExports, (e.g. interface + -- file not found) we get lots of spurious errors from 'filterImports' + returnRn (emptyRdrEnv, mkEmptyExportAvails imp_mod) + else + + filterImports imp_mod import_spec avails `thenRn` \ (filtered_avails, hides, explicits) -> + + -- Load all the home modules for the things being + -- bought into scope. This makes sure their fixities + -- are loaded before we grab the FixityEnv from Ifaces + let + home_modules = [name | avail <- filtered_avails, + -- Doesn't take account of hiding, but that doesn't matter + + -- Drop NotAvailables. + -- Happens if filterAvail finds something missing + case avail of + NotAvailable -> False + other -> True, + + let name = availName avail, + not (isLocallyDefined name || nameModule name == imp_mod) + -- Don't try to load the module being compiled + -- (this can happen in mutual-recursion situations) + -- or from the module being imported (it's already loaded) + ] + + same_module n1 n2 = nameModule n1 == nameModule n2 + load n = loadHomeInterface (doc_str n) n + doc_str n = ptext SLIT("Need fixities from") <+> ppr (nameModule n) <+> parens (ppr n) + in + mapRn load (nubBy same_module home_modules) `thenRn_` + + -- We 'improve' the provenance by setting + -- (a) the import-reason field, so that the Name says how it came into scope + -- including whether it's explicitly imported + -- (b) the print-unqualified field + -- But don't fiddle with wired-in things or we get in a twist + let + improve_prov name | isWiredInName name = name + | otherwise = setNameProvenance name (mk_new_prov name) + + is_explicit name = name `elemNameSet` explicits + mk_new_prov name = NonLocalDef (UserImport imp_mod iloc (is_explicit name)) + as_source + (rec_unqual_fn name) + in + qualifyImports imp_mod + (not qual_only) -- Maybe want unqualified names + as_mod hides + filtered_avails improve_prov `thenRn` \ (rdr_name_env, mod_avails) -> + + returnRn (rdr_name_env, mod_avails) \end{code} \begin{code} -type GlobalNameInfo = (BuiltinNames, - BuiltinKeys, - Name -> ExportFlag, - Name -> [RdrName]) - -type RnM_Info s r = RnMonad GlobalNameInfo s r - -getGlobalNames :: - IfaceCache - -> GlobalNameInfo - -> UniqSupply - -> RdrNameHsModule - -> PrimIO (RnEnv, - [Module], - Bag RenamedFixityDecl, - Bag Error, - Bag Warning) - -getGlobalNames iface_var info us - (HsModule mod _ _ imports _ ty_decls _ cls_decls _ _ _ binds _ _) - = case initRn True mod emptyRnEnv us1 - (setExtraRn info $ - getSourceNames ty_decls cls_decls binds) - of { ((src_vals, src_tcs), src_errs, src_warns) -> - - getImportedNames iface_var info us2 imports `thenPrimIO` - \ (imp_vals, imp_tcs, imp_mods, imp_fixes, imp_errs, imp_warns) -> +importsFromLocalDecls mod rec_exp_fn decls + = mapRn (getLocalDeclBinders newLocalName) decls `thenRn` \ avails_s -> let - unqual_vals = mapBag (\rn -> (Unqual (getLocalName rn), rn)) src_vals - unqual_tcs = mapBag (\rn -> (Unqual (getLocalName rn), rn)) src_tcs + avails = concat avails_s - all_vals = bagToList (unqual_vals `unionBags` imp_vals) - all_tcs = bagToList (unqual_tcs `unionBags` imp_tcs) + all_names :: [Name] -- All the defns; no dups eliminated + all_names = [name | avail <- avails, name <- availNames avail] - (all_env, dups) = extendGlobalRnEnv emptyRnEnv all_vals all_tcs + dups :: [[Name]] + dups = filter non_singleton (equivClassesByUniq getUnique all_names) + where + non_singleton (x1:x2:xs) = True + non_singleton other = False + in + -- Check for duplicate definitions + mapRn (addErrRn . dupDeclErr) dups `thenRn_` - dup_errs = map dup_err (equivClasses cmp_rdr (bagToList dups)) - cmp_rdr (rdr1,_,_) (rdr2,_,_) = cmp rdr1 rdr2 - dup_err ((rdr,rn,rn'):rest) = globalDupNamesErr rdr (rn:rn': [rn|(_,_,rn)<-rest]) + -- Record that locally-defined things are available + mapRn (recordSlurp Nothing Compulsory) avails `thenRn_` + + -- Build the environment + qualifyImports mod + True -- Want unqualified names + Nothing -- no 'as M' + [] -- Hide nothing + avails + (\n -> n) - all_errs = src_errs `unionBags` imp_errs `unionBags` listToBag dup_errs - all_warns = src_warns `unionBags` imp_warns - in - returnPrimIO (all_env, bagToList imp_mods, imp_fixes, all_errs, all_warns) - } where - (us1, us2) = splitUniqSupply us -\end{code} + newLocalName rdr_name loc = newLocallyDefinedGlobalName mod (rdrNameOcc rdr_name) + rec_exp_fn loc + +getLocalDeclBinders :: (RdrName -> SrcLoc -> RnMG Name) -- New-name function + -> RdrNameHsDecl + -> RnMG Avails +getLocalDeclBinders new_name (ValD binds) + = mapRn do_one (bagToList (collectTopBinders binds)) + where + do_one (rdr_name, loc) = new_name rdr_name loc `thenRn` \ name -> + returnRn (Avail name) -********************************************************* -* * -\subsection{Top-level source names} -* * -********************************************************* + -- foreign declarations +getLocalDeclBinders new_name (ForD (ForeignDecl nm kind _ dyn _ loc)) + | binds_haskell_name kind dyn + = new_name nm loc `thenRn` \ name -> + returnRn [Avail name] -\begin{code} -getSourceNames :: - [RdrNameTyDecl] - -> [RdrNameClassDecl] - -> RdrNameHsBinds - -> RnM_Info s (Bag RnName, -- values - Bag RnName) -- tycons/classes - -getSourceNames ty_decls cls_decls binds - = mapAndUnzipRn getTyDeclNames ty_decls `thenRn` \ (tycon_s, constrs_s) -> - mapAndUnzipRn getClassNames cls_decls `thenRn` \ (cls_s, cls_ops_s) -> - getTopBindsNames binds `thenRn` \ bind_names -> - returnRn (unionManyBags constrs_s `unionBags` - unionManyBags cls_ops_s `unionBags` bind_names, - listToBag tycon_s `unionBags` listToBag cls_s) - - -getTyDeclNames :: RdrNameTyDecl - -> RnM_Info s (RnName, Bag RnName) -- tycon and constrs - -getTyDeclNames (TyData _ tycon _ condecls _ _ src_loc) - = newGlobalName src_loc Nothing tycon `thenRn` \ tycon_name -> - mapRn (getConDeclName (Just (nameExportFlag tycon_name))) - condecls `thenRn` \ con_names -> - returnRn (RnData tycon_name con_names, - listToBag (map (\ n -> RnConstr n tycon_name) con_names)) - -getTyDeclNames (TyNew _ tycon _ condecls _ _ src_loc) - = newGlobalName src_loc Nothing tycon `thenRn` \ tycon_name -> - mapRn (getConDeclName (Just (nameExportFlag tycon_name))) - condecls `thenRn` \ con_names -> - returnRn (RnData tycon_name con_names, - listToBag (map (\ n -> RnConstr n tycon_name) con_names)) - -getTyDeclNames (TySynonym tycon _ _ src_loc) - = newGlobalName src_loc Nothing tycon `thenRn` \ tycon_name -> - returnRn (RnSyn tycon_name, emptyBag) - -getConDeclName exp (ConDecl con _ src_loc) - = newGlobalName src_loc exp con -getConDeclName exp (ConOpDecl _ op _ src_loc) - = newGlobalName src_loc exp op -getConDeclName exp (NewConDecl con _ src_loc) - = newGlobalName src_loc exp con -getConDeclName exp (RecConDecl con fields src_loc) - = panic "getConDeclName:RecConDecl" - newGlobalName src_loc exp con - - -getClassNames :: RdrNameClassDecl - -> RnM_Info s (RnName, Bag RnName) -- class and class ops - -getClassNames (ClassDecl _ cname _ sigs _ _ src_loc) - = newGlobalName src_loc Nothing cname `thenRn` \ class_name -> - getClassOpNames (Just (nameExportFlag class_name)) - sigs `thenRn` \ op_names -> - returnRn (RnClass class_name op_names, - listToBag (map (\ n -> RnClassOp n class_name) op_names)) - -getClassOpNames exp [] + | otherwise = returnRn [] -getClassOpNames exp (ClassOpSig op _ _ src_loc : sigs) - = newGlobalName src_loc exp op `thenRn` \ op_name -> - getClassOpNames exp sigs `thenRn` \ op_names -> - returnRn (op_name : op_names) -getClassOpNames exp (_ : sigs) - = getClassOpNames exp sigs + +getLocalDeclBinders new_name decl + = getDeclBinders new_name decl `thenRn` \ avail -> + case avail of + NotAvailable -> returnRn [] -- Instance decls and suchlike + other -> returnRn [avail] + +binds_haskell_name (FoImport _) _ = True +binds_haskell_name FoLabel _ = True +binds_haskell_name FoExport ext_nm = isDynamic ext_nm + +fixitiesFromLocalDecls :: GlobalRdrEnv -> [RdrNameHsDecl] -> RnMG FixityEnv +fixitiesFromLocalDecls gbl_env decls + = foldlRn getFixities emptyNameEnv decls + where + getFixities :: FixityEnv -> RdrNameHsDecl -> RnMG FixityEnv + getFixities acc (FixD fix) + = fix_decl acc fix + + getFixities acc (TyClD (ClassDecl _ _ _ sigs _ _ _ _ _)) + = foldlRn fix_decl acc [sig | FixSig sig <- sigs] + -- Get fixities from class decl sigs too + + getFixities acc other_decl + = returnRn acc + + fix_decl acc (FixitySig rdr_name fixity loc) + = -- Check for fixity decl for something not declared + case lookupRdrEnv gbl_env rdr_name of { + Nothing -> pushSrcLocRn loc $ + addWarnRn (unusedFixityDecl rdr_name fixity) `thenRn_` + returnRn acc ; + Just (name:_) -> + + -- Check for duplicate fixity decl + case lookupNameEnv acc name of { + Just (FixitySig _ _ loc') -> addErrRn (dupFixityDecl rdr_name loc loc') `thenRn_` + returnRn acc ; + + + Nothing -> returnRn (addToNameEnv acc name (FixitySig name fixity loc)) + }} \end{code} -********************************************************* -* * -\subsection{Bindings} -* * -********************************************************* +%************************************************************************ +%* * +\subsection{Filtering imports} +%* * +%************************************************************************ + +@filterImports@ takes the @ExportEnv@ telling what the imported module makes +available, and filters it through the import spec (if any). \begin{code} -getTopBindsNames :: RdrNameHsBinds - -> RnM_Info s (Bag RnName) - -getTopBindsNames binds = doBinds binds - -doBinds EmptyBinds = returnRn emptyBag -doBinds (SingleBind bind) = doBind bind -doBinds (BindWith bind sigs) = doBind bind -doBinds (ThenBinds binds1 binds2) - = andRn unionBags (doBinds binds1) (doBinds binds2) - -doBind EmptyBind = returnRn emptyBag -doBind (NonRecBind mbind) = doMBinds mbind -doBind (RecBind mbind) = doMBinds mbind - -doMBinds EmptyMonoBinds = returnRn emptyBag -doMBinds (PatMonoBind pat grhss_and_binds locn) = doPat locn pat -doMBinds (FunMonoBind p_name _ locn) = doName locn p_name -doMBinds (AndMonoBinds mbinds1 mbinds2) - = andRn unionBags (doMBinds mbinds1) (doMBinds mbinds2) - -doPats locn pats - = mapRn (doPat locn) pats `thenRn` \ pats_s -> - returnRn (unionManyBags pats_s) - -doPat locn WildPatIn = returnRn emptyBag -doPat locn (LitPatIn _) = returnRn emptyBag -doPat locn (LazyPatIn pat) = doPat locn pat -doPat locn (VarPatIn var) = doName locn var -doPat locn (NegPatIn pat) = doPat locn pat -doPat locn (ParPatIn pat) = doPat locn pat -doPat locn (ListPatIn pats) = doPats locn pats -doPat locn (TuplePatIn pats) = doPats locn pats -doPat locn (ConPatIn name pats) = doPats locn pats -doPat locn (ConOpPatIn p1 op p2) - = andRn unionBags (doPat locn p1) (doPat locn p2) -doPat locn (AsPatIn as_name pat) - = andRn unionBags (doName locn as_name) (doPat locn pat) -doPat locn (RecPatIn name fields) - = mapRn (doField locn) fields `thenRn` \ fields_s -> - returnRn (unionManyBags fields_s) - -doField locn (field, _, True{-pun-}) = doName locn field -doField locn (field, pat, _) = doPat locn pat - -doName locn rdr - = newGlobalName locn Nothing rdr `thenRn` \ name -> - returnRn (unitBag (RnName name)) +filterImports :: Module -- The module being imported + -> Maybe (Bool, [RdrNameIE]) -- Import spec; True => hiding + -> [AvailInfo] -- What's available + -> RnMG ([AvailInfo], -- What's actually imported + [AvailInfo], -- What's to be hidden (the unqualified version, that is) + NameSet) -- What was imported explicitly + + -- Complains if import spec mentions things that the module doesn't export + -- Warns/informs if import spec contains duplicates. +filterImports mod Nothing imports + = returnRn (imports, [], emptyNameSet) + +filterImports mod (Just (want_hiding, import_items)) avails + = mapRn check_item import_items `thenRn` \ item_avails -> + if want_hiding + then + -- All imported; item_avails to be hidden + returnRn (avails, item_avails, emptyNameSet) + else + -- Just item_avails imported; nothing to be hidden + returnRn (item_avails, [], availsToNameSet item_avails) + + where + import_fm :: FiniteMap OccName AvailInfo + import_fm = listToFM [ (nameOccName name, avail) + | avail <- avails, + name <- availNames avail] + -- Even though availNames returns data constructors too, + -- they won't make any difference because naked entities like T + -- in an import list map to TCOccs, not VarOccs. + + check_item item@(IEModuleContents _) + = addErrRn (badImportItemErr mod item) `thenRn_` + returnRn NotAvailable + + check_item item + | not (maybeToBool maybe_in_import_avails) || + (case filtered_avail of { NotAvailable -> True; other -> False }) + = addErrRn (badImportItemErr mod item) `thenRn_` + returnRn NotAvailable + + | dodgy_import = addWarnRn (dodgyImportWarn mod item) `thenRn_` + returnRn filtered_avail + + | otherwise = returnRn filtered_avail + + where + maybe_in_import_avails = lookupFM import_fm (ieOcc item) + Just avail = maybe_in_import_avails + filtered_avail = filterAvail item avail + dodgy_import = case (item, avail) of + (IEThingAll _, AvailTC _ [n]) -> True + -- This occurs when you import T(..), but + -- only export T abstractly. The single [n] + -- in the AvailTC is the type or class itself + + other -> False + \end{code} -********************************************************* -* * -\subsection{Creating a new global name} -* * -********************************************************* + + +%************************************************************************ +%* * +\subsection{Qualifiying imports} +%* * +%************************************************************************ + +@qualifyImports@ takes the @ExportEnv@ after filtering through the import spec +of an import decl, and deals with producing an @RnEnv@ with the +right qualified names. It also turns the @Names@ in the @ExportEnv@ into +fully fledged @Names@. \begin{code} -newGlobalName :: SrcLoc -> Maybe ExportFlag - -> RdrName -> RnM_Info s Name - -newGlobalName locn maybe_exp rdr - = getExtraRn `thenRn` \ (_,_,exp_fn,occ_fn) -> - getModuleRn `thenRn` \ mod -> - getSourceRn `thenRn` \ source -> - rnGetUnique `thenRn` \ u -> +qualifyImports :: Module -- Imported module + -> Bool -- True <=> want unqualified import + -> Maybe Module -- Optional "as M" part + -> [AvailInfo] -- What's to be hidden + -> Avails -- Whats imported and how + -> (Name -> Name) -- Improves the provenance on imported things + -> RnMG (GlobalRdrEnv, ExportAvails) + -- NB: the Names in ExportAvails don't have the improve-provenance + -- function applied to them + -- We could fix that, but I don't think it matters + +qualifyImports this_mod unqual_imp as_mod hides + avails improve_prov + = + -- Make the name environment. We're talking about a + -- single module here, so there must be no name clashes. + -- In practice there only ever will be if it's the module + -- being compiled. let - src_unqual = getLocalName rdr + -- Add the things that are available + name_env1 = foldl add_avail emptyRdrEnv avails - src_orig = if fromPrelude mod - then (Unqual src_unqual) - else (Qual mod src_unqual) + -- Delete things that are hidden + name_env2 = foldl del_avail name_env1 hides - exp = case maybe_exp of - Just exp -> exp - Nothing -> exp_fn n - - n = if source then - mkTopLevName u src_orig locn exp (occ_fn n) - else - mkImportedName u rdr locn exp (occ_fn n) + -- Create the export-availability info + export_avails = mkExportAvails qual_mod unqual_imp name_env2 avails in - addErrIfRn (source && isQual rdr) - (qualNameErr "name in definition" (rdr, locn)) `thenRn_` - returnRn n + returnRn (name_env2, export_avails) + + where + qual_mod = case as_mod of + Nothing -> this_mod + Just another_name -> another_name + + add_avail :: GlobalRdrEnv -> AvailInfo -> GlobalRdrEnv + add_avail env avail = foldl add_name env (availNames avail) + + add_name env name + | unqual_imp = env2 + | otherwise = env1 + where + env1 = addOneToGlobalRdrEnv env (Qual qual_mod occ err_hif) better_name + env2 = addOneToGlobalRdrEnv env1 (Unqual occ) better_name + occ = nameOccName name + better_name = improve_prov name + + del_avail env avail = foldl delOneFromGlobalRdrEnv env rdr_names + where + rdr_names = map (Unqual . nameOccName) (availNames avail) + +err_hif = error "qualifyImports: hif" -- Not needed in key to mapping \end{code} -********************************************************* -* * -\subsection{Imported names} -* * -********************************************************* + +%************************************************************************ +%* * +\subsection{Export list processing +%* * +%************************************************************************ + +Processing the export list. + +You might think that we should record things that appear in the export list as +``occurrences'' (using addOccurrenceName), but you'd be wrong. We do check (here) +that they are in scope, but there is no need to slurp in their actual declaration +(which is what addOccurrenceName forces). Indeed, doing so would big trouble when +compiling PrelBase, because it re-exports GHC, which includes takeMVar#, whose type +includes ConcBase.StateAndSynchVar#, and so on... \begin{code} -getImportedNames :: - IfaceCache - -> GlobalNameInfo -- builtin and knot name info - -> UniqSupply - -> [RdrNameImportDecl] -- import declarations - -> PrimIO (Bag (RdrName,RnName), -- imported values in scope - Bag (RdrName,RnName), -- imported tycons/classes in scope - Bag Module, -- directly imported modules - Bag RenamedFixityDecl, -- fixity info for imported names - Bag Error, - Bag Warning) - -getImportedNames iface_var info us imports - = returnPrimIO (builtin_vals, builtin_tcs, emptyBag, emptyBag, emptyBag, emptyBag) +type ExportAccum -- The type of the accumulating parameter of + -- the main worker function in exportsFromAvail + = ([Module], -- 'module M's seen so far + ExportOccMap, -- Tracks exported occurrence names + NameEnv AvailInfo) -- The accumulated exported stuff, kept in an env + -- so we can common-up related AvailInfos + +type ExportOccMap = FiniteMap OccName (Name, RdrNameIE) + -- Tracks what a particular exported OccName + -- in an export list refers to, and which item + -- it came from. It's illegal to export two distinct things + -- that have the same occurrence name + + +exportsFromAvail :: Module + -> Maybe [RdrNameIE] -- Export spec + -> ExportAvails + -> RnEnv + -> RnMG (Name -> ExportFlag, ExportEnv) + -- Complains if two distinct exports have same OccName + -- Warns about identical exports. + -- Complains about exports items not in scope +exportsFromAvail this_mod Nothing export_avails rn_env + = exportsFromAvail this_mod (Just [IEModuleContents this_mod]) export_avails rn_env + +exportsFromAvail this_mod (Just export_items) + (mod_avail_env, entity_avail_env) + (RnEnv global_name_env fixity_env) + = foldlRn exports_from_item + ([], emptyFM, emptyNameEnv) export_items `thenRn` \ (_, _, export_avail_map) -> + let + export_avails :: [AvailInfo] + export_avails = nameEnvElts export_avail_map + + export_names :: NameSet + export_names = availsToNameSet export_avails + + -- Export only those fixities that are for names that are + -- (a) defined in this module + -- (b) exported + export_fixities :: [(Name,Fixity)] + export_fixities = [ (name,fixity) + | FixitySig name fixity _ <- nameEnvElts fixity_env, + name `elemNameSet` export_names, + isLocallyDefined name + ] + + export_fn :: Name -> ExportFlag + export_fn = mk_export_fn export_names + in + returnRn (export_fn, ExportEnv export_avails export_fixities) + + where + exports_from_item :: ExportAccum -> RdrNameIE -> RnMG ExportAccum + + exports_from_item acc@(mods, occs, avails) ie@(IEModuleContents mod) + | mod `elem` mods -- Duplicate export of M + = warnCheckRn opt_WarnDuplicateExports + (dupModuleExport mod) `thenRn_` + returnRn acc + + | otherwise + = case lookupFM mod_avail_env mod of + Nothing -> failWithRn acc (modExportErr mod) + Just mod_avails -> foldlRn (check_occs ie) occs mod_avails `thenRn` \ occs' -> + let + avails' = foldl add_avail avails mod_avails + in + returnRn (mod:mods, occs', avails') + + exports_from_item acc@(mods, occs, avails) ie + | not (maybeToBool maybe_in_scope) + = failWithRn acc (unknownNameErr (ieName ie)) + + | not (null dup_names) + = addNameClashErrRn rdr_name (name:dup_names) `thenRn_` + returnRn acc + +#ifdef DEBUG + -- I can't see why this should ever happen; if the thing is in scope + -- at all it ought to have some availability + | not (maybeToBool maybe_avail) + = pprTrace "exportsFromAvail: curious Nothing:" (ppr name) + returnRn acc +#endif + + | not enough_avail + = failWithRn acc (exportItemErr ie export_avail) + + | otherwise -- Phew! It's OK! Now to check the occurrence stuff! + = check_occs ie occs export_avail `thenRn` \ occs' -> + returnRn (mods, occs', add_avail avails export_avail) + + where + rdr_name = ieName ie + maybe_in_scope = lookupFM global_name_env rdr_name + Just (name:dup_names) = maybe_in_scope + maybe_avail = lookupUFM entity_avail_env name + Just avail = maybe_avail + export_avail = filterAvail ie avail + enough_avail = case export_avail of {NotAvailable -> False; other -> True} + +add_avail avails avail = addToNameEnv_C plusAvail avails (availName avail) avail + +check_occs :: RdrNameIE -> ExportOccMap -> AvailInfo -> RnMG ExportOccMap +check_occs ie occs avail + = foldlRn check occs (availNames avail) where - -- For now jsut add the builtin names ... - (b_names,_,_,_) = info - builtin_vals = listToBag [(Unqual s, rn) | (s,rn) <- fmToList b_names, not (isRnTyCon rn)] - builtin_tcs = listToBag [(Unqual s, rn) | (s,rn) <- fmToList b_names, isRnTyCon rn] + check occs name + = case lookupFM occs name_occ of + Nothing -> returnRn (addToFM occs name_occ (name, ie)) + Just (name', ie') + | name == name' -> -- Duplicate export + warnCheckRn opt_WarnDuplicateExports + (dupExportWarn name_occ ie ie') `thenRn_` + returnRn occs + + | otherwise -> -- Same occ name but different names: an error + failWithRn occs (exportClashErr name_occ ie ie') + where + name_occ = nameOccName name + +mk_export_fn :: NameSet -> (Name -> ExportFlag) +mk_export_fn exported_names + = \name -> if name `elemNameSet` exported_names + then Exported + else NotExported \end{code} +%************************************************************************ +%* * +\subsection{Errors} +%* * +%************************************************************************ \begin{code} -globalDupNamesErr rdr rns sty - = ppHang (ppBesides [pprNonOp sty rdr, ppStr " multiply defined:"]) - 4 (ppAboves (map pp_def rns)) +badImportItemErr mod ie + = sep [ptext SLIT("Module"), quotes (pprModule mod), + ptext SLIT("does not export"), quotes (ppr ie)] + +dodgyImportWarn mod (IEThingAll tc) + = sep [ptext SLIT("Module") <+> quotes (pprModule mod) <+> ptext SLIT("exports") <+> quotes (ppr tc), + ptext SLIT("with no constructors/class operations;"), + ptext SLIT("yet it is imported with a (..)")] + +modExportErr mod + = hsep [ ptext SLIT("Unknown module in export list: module"), quotes (pprModule mod)] + +exportItemErr export_item NotAvailable + = sep [ ptext SLIT("Export item not in scope:"), quotes (ppr export_item)] + +exportItemErr export_item avail + = hang (ptext SLIT("Export item not fully in scope:")) + 4 (vcat [hsep [ptext SLIT("Wanted: "), ppr export_item], + hsep [ptext SLIT("Available:"), ppr (ieOcc export_item), pprAvail avail]]) + +exportClashErr occ_name ie1 ie2 + = hsep [ptext SLIT("The export items"), quotes (ppr ie1), ptext SLIT("and"), quotes (ppr ie2), + ptext SLIT("create conflicting exports for"), quotes (ppr occ_name)] + +dupDeclErr (n:ns) + = vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr n), + nest 4 (vcat (map pp sorted_ns))] where - pp_def rn = addShortErrLocLine (getSrcLoc rn) (\ sty -> ppr sty rn) sty + sorted_ns = sortLt occ'ed_before (n:ns) + + occ'ed_before a b = LT == compare (getSrcLoc a) (getSrcLoc b) + + pp n = pprProvenance (getNameProvenance n) + +dupExportWarn occ_name ie1 ie2 + = hsep [quotes (ppr occ_name), + ptext SLIT("is exported by"), quotes (ppr ie1), + ptext SLIT("and"), quotes (ppr ie2)] + +dupModuleExport mod + = hsep [ptext SLIT("Duplicate"), + quotes (ptext SLIT("Module") <+> pprModule mod), + ptext SLIT("in export list")] + +unusedFixityDecl rdr_name fixity + = hsep [ptext SLIT("Unused fixity declaration for"), quotes (ppr rdr_name)] + +dupFixityDecl rdr_name loc1 loc2 + = vcat [ptext SLIT("Multiple fixity declarations for") <+> quotes (ppr rdr_name), + ptext SLIT("at ") <+> ppr loc1, + ptext SLIT("and") <+> ppr loc2] - -- ToDo: print import src locs for imported names \end{code}