import DriverPhases ( isHsBoot )
import Util
import ListSetOps
-import Data.List ( partition, concatMap, (\\) )
+import Data.List ( partition, concatMap, (\\), delete )
import IO ( openFile, IOMode(..) )
import Monad ( when )
\end{code}
-- warning for {- SOURCE -} ones that are unnecessary
= do this_mod <- getModule
implicit_prelude <- doptM Opt_ImplicitPrelude
- let all_imports = mk_prel_imports this_mod implicit_prelude ++ imports
- (source, ordinary) = partition is_source_import all_imports
+ let prel_imports = mkPrelImports this_mod implicit_prelude imports
+ (source, ordinary) = partition is_source_import imports
is_source_import (L _ (ImportDecl _ is_boot _ _ _)) = is_boot
- stuff1 <- mapM (rnImportDecl this_mod) ordinary
+ stuff1 <- mapM (rnImportDecl this_mod) (prel_imports ++ 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
--- declarations, whereas the latter does.
- mk_prel_imports this_mod implicit_prelude
- | this_mod == pRELUDE
- || explicit_prelude_import
- || not implicit_prelude
- = []
- | otherwise = [preludeImportDecl]
- explicit_prelude_import
- = notNull [ () | L _ (ImportDecl mod _ _ _ _) <- imports,
- unLoc mod == pRELUDE_NAME ]
-
combine :: [(LImportDecl Name, GlobalRdrEnv, ImportAvails)]
-> ([LImportDecl Name], GlobalRdrEnv, ImportAvails)
combine = foldr plus ([], emptyGlobalRdrEnv, emptyImportAvails)
gbl_env1 `plusGlobalRdrEnv` gbl_env2,
imp_avails1 `plusImportAvails` imp_avails2)
-preludeImportDecl :: LImportDecl RdrName
-preludeImportDecl
- = L loc $
- ImportDecl (L loc pRELUDE_NAME)
+mkPrelImports :: Module -> Bool -> [LImportDecl RdrName] -> [LImportDecl RdrName]
+-- Consruct the implicit declaration "import Prelude" (or not)
+--
+-- NB: opt_NoImplicitPrelude is slightly different to import Prelude ();
+-- because the former doesn't even look at Prelude.hi for instance
+-- declarations, whereas the latter does.
+mkPrelImports this_mod implicit_prelude import_decls
+ | this_mod == pRELUDE
+ || explicit_prelude_import
+ || not implicit_prelude
+ = []
+ | otherwise = [preludeImportDecl]
+ where
+ explicit_prelude_import
+ = notNull [ () | L _ (ImportDecl mod _ _ _ _) <- import_decls,
+ unLoc mod == pRELUDE_NAME ]
+
+ preludeImportDecl :: LImportDecl RdrName
+ preludeImportDecl
+ = L loc $
+ ImportDecl (L loc pRELUDE_NAME)
False {- Not a boot interface -}
False {- Not qualified -}
Nothing {- No "as" -}
Nothing {- No import list -}
- where
- loc = mkGeneralSrcSpan FSLIT("Implicit import declaration")
-
+ loc = mkGeneralSrcSpan FSLIT("Implicit import declaration")
+
rnImportDecl :: Module
-> LImportDecl RdrName
-- filter the imports according to the import declaration
(new_imp_details, gbl_env) <-
- filterImports2 iface imp_spec imp_details total_avails
+ filterImports iface imp_spec imp_details total_avails
dflags <- getDOpts
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
-- 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 = nameEnvElts (mkAvailEnv avails)
+nubAvails avails = map normaliseAvail . nameEnvElts . mkAvailEnv $ avails
\end{code}
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
do_litem :: ExportAccum -> LIE RdrName -> RnM ExportAccum