+\begin{code}
+filterAvail :: IE RdrName -- Wanted
+ -> AvailInfo -- Available
+ -> Maybe AvailInfo -- Resulting available;
+ -- Nothing if (any of the) wanted stuff isn't there
+
+filterAvail ie@(IEThingWith want wants) avail@(AvailTC n ns)
+ | sub_names_ok = Just (AvailTC n (filter is_wanted ns))
+ | otherwise = Nothing
+ where
+ is_wanted name = nameOccName name `elem` wanted_occs
+ sub_names_ok = all (`elem` avail_occs) wanted_occs
+ avail_occs = map nameOccName ns
+ wanted_occs = map rdrNameOcc (want:wants)
+
+filterAvail (IEThingAbs _) (AvailTC n ns) = ASSERT( n `elem` ns )
+ Just (AvailTC n [n])
+
+filterAvail (IEThingAbs _) avail@(Avail n) = Just avail -- Type synonyms
+
+filterAvail (IEVar _) avail@(Avail n) = Just avail
+filterAvail (IEVar v) avail@(AvailTC n ns) = Just (AvailTC n (filter wanted ns))
+ where
+ wanted n = nameOccName n == occ
+ occ = rdrNameOcc v
+ -- The second equation happens if we import a class op, thus
+ -- import A( op )
+ -- where op is a class operation
+
+filterAvail (IEThingAll _) avail@(AvailTC _ _) = Just avail
+ -- We don't complain even if the IE says T(..), but
+ -- no constrs/class ops of T are available
+ -- Instead that's caught with a warning by the caller
+
+filterAvail ie avail = Nothing
+\end{code}
+
+
+%************************************************************************
+%* *
+\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}
+type ExportAccum -- The type of the accumulating parameter of
+ -- the main worker function in exportsFromAvail
+ = ([ModuleName], -- 'module M's seen so far
+ ExportOccMap, -- Tracks exported occurrence names
+ AvailEnv) -- The accumulated exported stuff, kept in an env
+ -- so we can common-up related AvailInfos
+emptyExportAccum = ([], emptyOccEnv, emptyAvailEnv)
+
+type ExportOccMap = OccEnv (Name, IE RdrName)
+ -- 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 :: Bool -- False => no 'module M(..) where' header at all
+ -> Maybe [Located (IE RdrName)] -- Nothing => no explicit export list
+ -> RnM Avails
+ -- Complains if two distinct exports have same OccName
+ -- Warns about identical exports.
+ -- Complains about exports items not in scope
+
+exportsFromAvail explicit_mod exports
+ = do { TcGblEnv { tcg_rdr_env = rdr_env,
+ tcg_imports = imports } <- getGblEnv ;
+
+ -- If the module header is omitted altogether, then behave
+ -- as if the user had written "module Main(main) where..."
+ -- EXCEPT in interactive mode, when we behave as if he had
+ -- written "module Main where ..."
+ -- Reason: don't want to complain about 'main' not in scope
+ -- in interactive mode
+ ghci_mode <- getGhciMode ;
+ let { real_exports
+ | explicit_mod = exports
+ | ghci_mode == Interactive = Nothing
+ | otherwise = Just [noLoc (IEVar main_RDR_Unqual)] } ;
+ exports_from_avail real_exports rdr_env imports }
+
+
+exports_from_avail Nothing rdr_env
+ imports@(ImportAvails { imp_env = entity_avail_env })
+ = -- Export all locally-defined things
+ -- We do this by filtering the global RdrEnv,
+ -- keeping only things that are (a) qualified,
+ -- (b) locally defined, (c) a 'main' name
+ -- Then we look up in the entity-avail-env
+ return [ lookupAvailEnv entity_avail_env name
+ | gre <- globalRdrEnvElts rdr_env,
+ isLocalGRE gre,
+ let name = gre_name gre,
+ isNothing (nameParent_maybe name) -- Main things only
+ ]
+
+exports_from_avail (Just export_items) rdr_env
+ (ImportAvails { imp_qual = mod_avail_env,
+ imp_env = entity_avail_env })
+ = foldlM (exports_from_litem) emptyExportAccum
+ export_items `thenM` \ (_, _, export_avail_map) ->
+ returnM (nameEnvElts export_avail_map)
+
+ where
+ exports_from_litem :: ExportAccum -> Located (IE RdrName) -> RnM ExportAccum
+ exports_from_litem acc = addLocM (exports_from_item acc)
+
+ exports_from_item :: ExportAccum -> IE RdrName -> RnM ExportAccum
+ exports_from_item acc@(mods, occs, avails) ie@(IEModuleContents mod)
+ | mod `elem` mods -- Duplicate export of M
+ = do { warn_dup_exports <- doptM Opt_WarnDuplicateExports ;
+ warnIf warn_dup_exports (dupModuleExport mod) ;
+ returnM acc }
+
+ | otherwise
+ = case lookupModuleEnvByName mod_avail_env mod of
+ Nothing -> addErr (modExportErr mod) `thenM_`
+ returnM acc
+
+ Just avail_env
+ -> let
+ mod_avails = [ filtered_avail
+ | avail <- availEnvElts avail_env,
+ let mb_avail = filter_unqual rdr_env avail,
+ isJust mb_avail,
+ let Just filtered_avail = mb_avail]
+
+ avails' = foldl addAvail avails mod_avails
+ in
+ -- 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.
+
+ foldlM (check_occs ie) occs mod_avails `thenM` \ occs' ->
+ returnM (mod:mods, occs', avails')
+
+ exports_from_item acc@(mods, occs, avails) ie
+ = lookupGlobalOccRn (ieName ie) `thenM` \ name ->
+ if isUnboundName name then
+ returnM acc -- Avoid error cascade
+ else
+ -- Get the AvailInfo for the parent of the specified name
+ let
+ parent = nameParent name
+ avail = lookupAvailEnv entity_avail_env parent
+ in
+ -- Filter out the bits we want
+ case filterAvail ie avail of {
+ Nothing -> -- Not enough availability
+ addErr (exportItemErr ie) `thenM_`
+ returnM acc ;
+
+ Just export_avail ->
+
+ -- Phew! It's OK! Now to check the occurrence stuff!
+ checkForDodgyExport ie avail `thenM_`
+ check_occs ie occs export_avail `thenM` \ occs' ->
+ returnM (mods, occs', addAvail avails export_avail)
+ }
+
+
+-------------------------------
+filter_unqual :: GlobalRdrEnv -> AvailInfo -> Maybe AvailInfo
+-- Filter the Avail by what's in scope unqualified
+filter_unqual env (Avail n)
+ | in_scope env n = Just (Avail n)
+ | otherwise = Nothing
+filter_unqual env (AvailTC n ns)
+ | not (null ns') = Just (AvailTC n ns')
+ | otherwise = Nothing
+ where
+ ns' = filter (in_scope env) ns
+
+in_scope :: GlobalRdrEnv -> Name -> Bool
+-- Checks whether the Name is in scope unqualified,
+-- regardless of whether it's ambiguous or not
+in_scope env n = any unQualOK (lookupGRE_Name env n)
+
+-------------------------------
+checkForDodgyExport :: IE RdrName -> AvailInfo -> RnM ()
+checkForDodgyExport (IEThingAll tc) (AvailTC _ [n]) = addWarn (dodgyExportWarn tc)
+ -- This occurs when you import T(..), but
+ -- only export T abstractly. The single [n]
+ -- in the AvailTC is the type or class itself
+checkForDodgyExport _ _ = return ()
+
+-------------------------------
+check_occs :: IE RdrName -> ExportOccMap -> AvailInfo -> RnM ExportOccMap
+check_occs ie occs avail
+ = foldlM check occs (availNames avail)
+ where
+ check occs name
+ = case lookupOccEnv occs name_occ of
+ Nothing -> returnM (extendOccEnv occs name_occ (name, ie))
+
+ Just (name', ie')
+ | name == name' -- Duplicate export
+ -> do { warn_dup_exports <- doptM Opt_WarnDuplicateExports ;
+ warnIf warn_dup_exports (dupExportWarn name_occ ie ie') ;
+ returnM occs }
+
+ | otherwise -- Same occ name but different names: an error
+ -> do { global_env <- getGlobalRdrEnv ;
+ addErr (exportClashErr global_env name name' ie ie') ;
+ returnM occs }
+ where
+ name_occ = nameOccName name
+\end{code}
+
+%*********************************************************
+%* *
+ Deprecations
+%* *
+%*********************************************************
+
+\begin{code}
+reportDeprecations :: TcGblEnv -> RnM ()
+reportDeprecations tcg_env
+ = ifOptM Opt_WarnDeprecations $
+ do { hpt <- getHpt
+ ; eps <- getEps
+ ; mapM_ (check hpt (eps_PIT eps)) all_gres }
+ where
+ used_names = findUses (tcg_dus tcg_env) emptyNameSet
+ all_gres = globalRdrEnvElts (tcg_rdr_env tcg_env)
+
+ check hpt pit (GRE {gre_name = name, gre_prov = Imported (imp_spec:_) _})
+ | name `elemNameSet` used_names
+ , Just deprec_txt <- lookupDeprec hpt pit name
+ = addSrcSpan (is_loc imp_spec) $
+ addWarn (sep [ptext SLIT("Deprecated use of") <+>
+ text (occNameFlavour (nameOccName name)) <+>
+ quotes (ppr name),
+ (parens imp_msg),
+ (ppr deprec_txt) ])
+ where
+ name_mod = nameModuleName name
+ imp_mod = is_mod imp_spec
+ imp_msg = ptext SLIT("imported from") <+> ppr imp_mod <> extra
+ extra | imp_mod == name_mod = empty
+ | otherwise = ptext SLIT(", but defined in") <+> ppr name_mod
+
+ check hpt pit ok_gre = returnM () -- Local, or not used, or not deprectated
+ -- The Imported pattern-match: don't deprecate locally defined names
+ -- For a start, we may be exporting a deprecated thing
+ -- Also we may use a deprecated thing in the defn of another
+ -- deprecated things. We may even use a deprecated thing in
+ -- the defn of a non-deprecated thing, when changing a module's
+ -- interface
+
+lookupDeprec :: HomePackageTable -> PackageIfaceTable
+ -> Name -> Maybe DeprecTxt
+lookupDeprec hpt pit n
+ = case lookupIface hpt pit (nameModule n) of
+ Just iface -> mi_dep_fn iface n `seqMaybe` -- Bleat if the thing, *or
+ mi_dep_fn iface (nameParent n) -- its parent*, is deprec'd
+ Nothing -> pprPanic "lookupDeprec" (ppr n)
+ -- 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
+\end{code}
+
+%*********************************************************
+%* *
+ Unused names
+%* *
+%*********************************************************