#include "HsVersions.h"
import CmdLineOpts ( opt_NoImplicitPrelude, opt_WarnDuplicateExports,
- opt_SourceUnchanged
+ opt_SourceUnchanged, opt_WarnUnusedBinds
)
import HsSyn ( HsModule(..), ImportDecl(..), HsDecl(..), TyClDecl(..),
IE(..), ieName,
- ForeignDecl(..), ExtName(..), ForKind(..),
+ ForeignDecl(..), ForKind(..), isDynamic,
FixitySig(..), Sig(..),
collectTopBinders
)
-import RdrHsSyn ( RdrName(..), RdrNameIE, RdrNameImportDecl,
- RdrNameHsModule, RdrNameHsDecl,
- rdrNameOcc, ieOcc
+import RdrHsSyn ( RdrNameIE, RdrNameImportDecl,
+ RdrNameHsModule, RdrNameHsDecl
)
import RnIfaces ( getInterfaceExports, getDeclBinders, getImportedFixities,
- recordSlurp, checkUpToDate, loadHomeInterface
+ recordSlurp, checkUpToDate
)
-import BasicTypes ( IfaceFlavour(..) )
import RnEnv
import RnMonad
import UniqFM ( lookupUFM )
import Bag ( bagToList )
import Maybes ( maybeToBool )
+import Module ( pprModule )
+import NameSet
import Name
+import RdrName ( RdrName, rdrNameOcc, mkRdrQual, mkRdrUnqual )
import SrcLoc ( SrcLoc )
import NameSet ( elemNameSet, emptyNameSet )
import Outputable
import Unique ( getUnique )
-import Util ( removeDups, equivClassesByUniq )
-import List ( nubBy )
+import Util ( removeDups, equivClassesByUniq, sortLt )
\end{code}
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_exported_avails, _) ->
fixRn (\ ~(rec_rn_env, _) ->
let
rec_unqual_fn :: Name -> Bool -- Is this chap in scope unqualified?
- rec_unqual_fn = mkPrintUnqualFn rec_rn_env
+ rec_unqual_fn = unQualInScope rec_rn_env
+
+ rec_exp_fn :: Name -> ExportFlag
+ rec_exp_fn = mk_export_fn (availsToNameSet rec_exported_avails)
in
+ setOmitQualFn rec_unqual_fn $
+ setModuleRn this_mod $
+
-- 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 rec_unqual_fn)
- all_imports `thenRn` \ (imp_gbl_envs, imp_avails_s) ->
+ mapAndUnzipRn importsFromImportDecl all_imports `thenRn` \ (imp_gbl_envs, imp_avails_s) ->
-- COMBINE RESULTS
-- We put the local env second, so that a local provenance
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
+ all_avails :: ExportAvails
+ all_avails = foldr plusExportAvails local_mod_avails imp_avails_s
in
- returnRn (gbl_env, export_avails)
- ) `thenRn` \ (gbl_env, export_avails) ->
+ returnRn (gbl_env, all_avails)
+ ) `thenRn` \ (gbl_env, all_avails) ->
-- TRY FOR EARLY EXIT
-- We can't go for an early exit before this because we have to check
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) ->
+ exportsFromAvail this_mod exports all_avails gbl_env `thenRn` \ exported_avails ->
-- DONE
- returnRn (export_fn, Just (export_env, rn_env, global_avail_env))
- ) `thenRn` \ (_, result) ->
- returnRn result
+ returnRn (exported_avails, Just (all_avails, gbl_env))
+ ) `thenRn` \ (exported_avails, maybe_stuff) ->
+
+ case maybe_stuff of {
+ Nothing -> returnRn Nothing ;
+ Just (all_avails, gbl_env) ->
+
+
+ -- DEAL WITH FIXITIES
+ fixitiesFromLocalDecls gbl_env decls `thenRn` \ local_fixity_env ->
+ getImportedFixities gbl_env `thenRn` \ imp_fixity_env ->
+ let
+ -- Export only those fixities that are for names that are
+ -- (a) defined in this module
+ -- (b) exported
+ exported_fixities :: [(Name,Fixity)]
+ exported_fixities = [(name,fixity) | FixitySig name fixity _ <- nameEnvElts local_fixity_env,
+ isLocallyDefined name
+ ]
+
+ fixity_env = imp_fixity_env `plusNameEnv` local_fixity_env
+ in
+ traceRn (text "fixity env" <+> vcat (map ppr (nameEnvElts fixity_env))) `thenRn_`
+
+ --- TIDY UP
+ let
+ export_env = ExportEnv exported_avails exported_fixities
+ rn_env = RnEnv gbl_env fixity_env
+ (_, global_avail_env) = all_avails
+ in
+ returnRn (Just (export_env, rn_env, global_avail_env))
+ }
where
junk_exp_fn = error "RnNames:export_fn"
| 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 ])
+ = not (null [ () | (ImportDecl mod qual _ _ _) <- imports, mod == pRELUDE ])
\end{code}
\begin{code}
\end{code}
\begin{code}
-importsFromImportDecl :: (Name -> Bool) -- True => print unqualified
- -> RdrNameImportDecl
+importsFromImportDecl :: RdrNameImportDecl
-> RnMG (GlobalRdrEnv,
ExportAvails)
-importsFromImportDecl rec_unqual_fn (ImportDecl mod qual_only as_source as_mod import_spec iloc)
+importsFromImportDecl (ImportDecl imp_mod qual_only as_mod import_spec iloc)
= pushSrcLocRn iloc $
- getInterfaceExports mod as_source `thenRn` \ avails ->
+ getInterfaceExports imp_mod `thenRn` \ (imp_mod, avails) ->
if null avails then
-- If there's an error in getInterfaceExports, (e.g. interface
- -- file not found) then avail might be NotAvailable, so availName
- -- in home_modules fails. Hence the guard here. Also we get lots
- -- of spurious errors from 'filterImports' if we don't find the interface file
- returnRn (emptyRdrEnv, mkEmptyExportAvails mod)
+ -- file not found) we get lots of spurious errors from 'filterImports'
+ returnRn (emptyRdrEnv, mkEmptyExportAvails imp_mod)
else
- filterImports mod import_spec avails `thenRn` \ (filtered_avails, hides, explicits) ->
+ 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
-
- let name = availName avail,
- nameModule name /= mod]
- -- This predicate is a bit of a hack.
- -- PrelBase imports error from PrelErr.hi-boot; but error is
- -- wired in, so its provenance doesn't say it's from an hi-boot
- -- file. Result: disaster when PrelErr.hi doesn't exist.
-
- 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 mod iloc (is_explicit name))
- as_source
- (rec_unqual_fn name)
+ improve_prov name = setNameImportReason name (UserImport imp_mod iloc (is_explicit name))
+ is_explicit name = name `elemNameSet` explicits
in
- qualifyImports mod
+ qualifyImports imp_mod
(not qual_only) -- Maybe want unqualified names
as_mod hides
filtered_avails improve_prov `thenRn` \ (rdr_name_env, mod_avails) ->
non_singleton other = False
in
-- Check for duplicate definitions
- mapRn (addErrRn . dupDeclErr) dups `thenRn_`
+ mapRn_ (addErrRn . dupDeclErr) dups `thenRn_`
-- Record that locally-defined things are available
- mapRn (recordSlurp Nothing Compulsory) avails `thenRn_`
+ mapRn_ (recordSlurp Nothing Compulsory) avails `thenRn_`
-- Build the environment
qualifyImports mod
do_one (rdr_name, loc) = new_name rdr_name loc `thenRn` \ name ->
returnRn (Avail name)
- -- foreign import declaration
-getLocalDeclBinders new_name (ForD (ForeignDecl nm kind _ _ _ loc))
- | binds_haskell_name kind
+ -- 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]
= returnRn []
getLocalDeclBinders new_name decl
- = getDeclBinders new_name decl `thenRn` \ avail ->
- case avail of
- NotAvailable -> returnRn [] -- Instance decls and suchlike
- other -> returnRn [avail]
+ = getDeclBinders new_name decl `thenRn` \ maybe_avail ->
+ case maybe_avail of
+ Nothing -> returnRn [] -- Instance decls and suchlike
+ Just avail -> returnRn [avail]
-binds_haskell_name (FoImport _) = True
-binds_haskell_name FoLabel = True
-binds_haskell_name FoExport = False
+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
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
-
+ -- 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 ;
+ Nothing | opt_WarnUnusedBinds
+ -> pushSrcLocRn loc (addWarnRn (unusedFixityDecl rdr_name fixity)) `thenRn_`
+ returnRn acc
+ | otherwise -> returnRn acc ;
+
Just (name:_) ->
-- Check for duplicate fixity decl
available, and filters it through the import spec (if any).
\begin{code}
-filterImports :: Module
+filterImports :: Module -- The module being imported
-> Maybe (Bool, [RdrNameIE]) -- Import spec; True => hiding
-> [AvailInfo] -- What's available
-> RnMG ([AvailInfo], -- What's actually imported
= returnRn (imports, [], emptyNameSet)
filterImports mod (Just (want_hiding, import_items)) avails
- = mapRn check_item import_items `thenRn` \ item_avails ->
+ = mapMaybeRn check_item import_items `thenRn` \ avails_w_explicits ->
+ let
+ (item_avails, explicits_s) = unzip avails_w_explicits
+ explicits = foldl addListToNameSet emptyNameSet explicits_s
+ in
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)
-
+ returnRn (item_avails, [], explicits)
where
import_fm :: FiniteMap OccName AvailInfo
import_fm = listToFM [ (nameOccName name, avail)
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.
+ -- in an import list map to TcOccs, not VarOccs.
check_item item@(IEModuleContents _)
= addErrRn (badImportItemErr mod item) `thenRn_`
- returnRn NotAvailable
+ returnRn Nothing
check_item item
| not (maybeToBool maybe_in_import_avails) ||
- (case filtered_avail of { NotAvailable -> True; other -> False })
+ not (maybeToBool maybe_filtered_avail)
= addErrRn (badImportItemErr mod item) `thenRn_`
- returnRn NotAvailable
+ returnRn Nothing
| dodgy_import = addWarnRn (dodgyImportWarn mod item) `thenRn_`
- returnRn filtered_avail
+ returnRn (Just (filtered_avail, explicits))
- | otherwise = returnRn filtered_avail
+ | otherwise = returnRn (Just (filtered_avail, explicits))
where
- maybe_in_import_avails = lookupFM import_fm (ieOcc item)
+ wanted_occ = rdrNameOcc (ieName item)
+ maybe_in_import_avails = lookupFM import_fm wanted_occ
+
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
+ maybe_filtered_avail = filterAvail item avail
+ Just filtered_avail = maybe_filtered_avail
+ explicits | dot_dot = [availName filtered_avail]
+ | otherwise = availNames filtered_avail
+
+ dot_dot = case item of
+ IEThingAll _ -> True
+ other -> False
+
+ 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}
| unqual_imp = env2
| otherwise = env1
where
- env1 = addOneToGlobalRdrEnv env (Qual qual_mod occ err_hif) better_name
- env2 = addOneToGlobalRdrEnv env1 (Unqual occ) better_name
+ env1 = addOneToGlobalRdrEnv env (mkRdrQual qual_mod occ) better_name
+ env2 = addOneToGlobalRdrEnv env1 (mkRdrUnqual 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
+ rdr_names = map (mkRdrUnqual . nameOccName) (availNames avail)
\end{code}
exportsFromAvail :: Module
-> Maybe [RdrNameIE] -- Export spec
-> ExportAvails
- -> RnEnv
- -> RnMG (Name -> ExportFlag, ExportEnv)
+ -> GlobalRdrEnv
+ -> RnMG Avails
-- 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 Nothing export_avails global_name_env
+ = exportsFromAvail this_mod (Just [IEModuleContents this_mod])
+ export_avails global_name_env
exportsFromAvail this_mod (Just export_items)
(mod_avail_env, entity_avail_env)
- (RnEnv global_name_env fixity_env)
+ global_name_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)
+ returnRn export_avails
where
exports_from_item :: ExportAccum -> RdrNameIE -> RnMG ExportAccum
#endif
| not enough_avail
- = failWithRn acc (exportItemErr ie export_avail)
+ = failWithRn acc (exportItemErr ie)
| otherwise -- Phew! It's OK! Now to check the occurrence stuff!
= check_occs ie occs export_avail `thenRn` \ occs' ->
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}
+ maybe_avail = lookupUFM entity_avail_env name
+ Just avail = maybe_avail
+ maybe_export_avail = filterAvail ie avail
+ enough_avail = maybeToBool maybe_export_avail
+ Just export_avail = maybe_export_avail
add_avail avails avail = addToNameEnv_C plusAvail avails (availName avail) avail
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]])
+exportItemErr export_item
+ = sep [ ptext SLIT("Bad export item"), quotes (ppr export_item)]
exportClashErr occ_name ie1 ie2
= hsep [ptext SLIT("The export items"), quotes (ppr ie1), ptext SLIT("and"), quotes (ppr ie2),
dupDeclErr (n:ns)
= vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr n),
- nest 4 (vcat (map pp (n:ns)))]
+ nest 4 (vcat (map pp sorted_ns))]
where
- pp n = pprProvenance (getNameProvenance n)
+ 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),