[project @ 2001-02-28 11:44:39 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / RnNames.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
3 %
4 \section[RnNames]{Extracting imported and top-level names in scope}
5
6 \begin{code}
7 module RnNames (
8         getGlobalNames, exportsFromAvail
9     ) where
10
11 #include "HsVersions.h"
12
13 import CmdLineOpts      ( DynFlag(..) )
14
15 import HsSyn            ( HsModule(..), HsDecl(..), IE(..), ieName, ImportDecl(..),
16                           ForeignDecl(..), ForKind(..), isDynamicExtName,
17                           collectLocatedHsBinders
18                         )
19 import RdrHsSyn         ( RdrNameIE, RdrNameImportDecl,
20                           RdrNameHsModule, RdrNameHsDecl
21                         )
22 import RnIfaces         ( recordLocalSlurps )
23 import RnHiFiles        ( getTyClDeclBinders, loadInterface )
24 import RnEnv
25 import RnMonad
26
27 import FiniteMap
28 import PrelNames        ( pRELUDE_Name, mAIN_Name, main_RDR_Unqual, isUnboundName )
29 import UniqFM           ( lookupUFM )
30 import Module           ( ModuleName, moduleName, WhereFrom(..) )
31 import NameSet
32 import Name             ( Name, nameSrcLoc, nameOccName,  nameEnvElts )
33 import HscTypes         ( Provenance(..), ImportReason(..), GlobalRdrEnv,
34                           GenAvailInfo(..), AvailInfo, Avails, AvailEnv, 
35                           Deprecations(..), ModIface(..)
36                         )
37 import RdrName          ( rdrNameOcc, setRdrNameOcc )
38 import OccName          ( setOccNameSpace, dataName )
39 import NameSet          ( elemNameSet, emptyNameSet )
40 import Outputable
41 import Maybes           ( maybeToBool, catMaybes, mapMaybe )
42 import UniqFM           ( emptyUFM, listToUFM )
43 import ListSetOps       ( removeDups )
44 import Util             ( sortLt )
45 import List             ( partition )
46 \end{code}
47
48
49
50 %************************************************************************
51 %*                                                                      *
52 \subsection{Get global names}
53 %*                                                                      *
54 %************************************************************************
55
56 \begin{code}
57 getGlobalNames :: Module -> RdrNameHsModule
58                -> RnMG (GlobalRdrEnv,   -- Maps all in-scope things
59                         GlobalRdrEnv,   -- Maps just *local* things
60                         ExportAvails)   -- The exported stuff
61
62 getGlobalNames this_mod (HsModule _ _ _ imports decls _ mod_loc)
63   =             -- PROCESS LOCAL DECLS
64                 -- Do these *first* so that the correct provenance gets
65                 -- into the global name cache.
66         importsFromLocalDecls this_mod decls            `thenRn` \ (local_gbl_env, local_mod_avails) ->
67
68                 -- PROCESS IMPORT DECLS
69                 -- Do the non {- SOURCE -} ones first, so that we get a helpful
70                 -- warning for {- SOURCE -} ones that are unnecessary
71         doptRn Opt_NoImplicitPrelude                            `thenRn` \ opt_no_prelude -> 
72         let
73           all_imports        = mk_prel_imports opt_no_prelude ++ imports
74           (source, ordinary) = partition is_source_import all_imports
75           is_source_import (ImportDecl _ ImportByUserSource _ _ _ _) = True
76           is_source_import other                                     = False
77
78           get_imports = importsFromImportDecl this_mod_name
79         in
80         mapAndUnzipRn get_imports ordinary      `thenRn` \ (imp_gbl_envs1, imp_avails_s1) ->
81         mapAndUnzipRn get_imports source        `thenRn` \ (imp_gbl_envs2, imp_avails_s2) ->
82
83                 -- COMBINE RESULTS
84                 -- We put the local env second, so that a local provenance
85                 -- "wins", even if a module imports itself.
86         let
87             gbl_env :: GlobalRdrEnv
88             imp_gbl_env = foldr plusGlobalRdrEnv emptyRdrEnv (imp_gbl_envs2 ++ imp_gbl_envs1)
89             gbl_env     = imp_gbl_env `plusGlobalRdrEnv` local_gbl_env
90
91             all_avails :: ExportAvails
92             all_avails = foldr plusExportAvails local_mod_avails (imp_avails_s2 ++ imp_avails_s1)
93         in
94
95                 -- ALL DONE
96         returnRn (gbl_env, local_gbl_env, all_avails)
97   where
98     this_mod_name = moduleName this_mod
99
100         -- NB: opt_NoImplicitPrelude is slightly different to import Prelude ();
101         -- because the former doesn't even look at Prelude.hi for instance declarations,
102         -- whereas the latter does.
103     mk_prel_imports no_prelude
104         | this_mod_name == pRELUDE_Name ||
105           explicit_prelude_import ||
106           no_prelude
107         = []
108
109         | otherwise = [ImportDecl pRELUDE_Name
110                                   ImportByUser
111                                   False {- Not qualified -}
112                                   Nothing       {- No "as" -}
113                                   Nothing       {- No import list -}
114                                   mod_loc]
115     
116     explicit_prelude_import
117       = not (null [ () | (ImportDecl mod _ _ _ _ _) <- imports, mod == pRELUDE_Name ])
118 \end{code}
119         
120 \begin{code}
121 importsFromImportDecl :: ModuleName
122                       -> RdrNameImportDecl
123                       -> RnMG (GlobalRdrEnv, 
124                                ExportAvails) 
125
126 importsFromImportDecl this_mod_name (ImportDecl imp_mod_name from qual_only as_mod import_spec iloc)
127   = pushSrcLocRn iloc $
128
129     loadInterface (ppr imp_mod_name <+> ptext SLIT("is directly imported"))
130                   imp_mod_name from                     `thenRn` \ iface ->
131     let
132         imp_mod          = mi_module iface
133         avails_by_module = mi_exports iface
134         deprecs          = mi_deprecs iface
135
136         avails :: Avails
137         avails = [ avail | (mod_name, avails) <- avails_by_module,
138                            mod_name /= this_mod_name,
139                            avail <- avails ]
140         -- If the module exports anything defined in this module, just ignore it.
141         -- Reason: otherwise it looks as if there are two local definition sites
142         -- for the thing, and an error gets reported.  Easiest thing is just to
143         -- filter them out up front. This situation only arises if a module
144         -- imports itself, or another module that imported it.  (Necessarily,
145         -- this invoves a loop.)  
146         --
147         -- Tiresome consequence: if you say
148         --      module A where
149         --         import B( AType )
150         --         type AType = ...
151         --
152         --      module B( AType ) where
153         --         import {-# SOURCE #-} A( AType )
154         --
155         -- then you'll get a 'B does not export AType' message.  Oh well.
156
157     in
158     if null avails_by_module then
159         -- If there's an error in loadInterface, (e.g. interface
160         -- file not found) we get lots of spurious errors from 'filterImports'
161         returnRn (emptyRdrEnv, mkEmptyExportAvails imp_mod_name)
162     else
163
164         -- Complain if we import a deprecated module
165     (case deprecs of    
166         DeprecAll txt -> addWarnRn (moduleDeprec imp_mod_name txt)
167         other         -> returnRn ()
168     )                                                   `thenRn_`
169
170         -- Filter the imports according to the import list
171     filterImports imp_mod_name from import_spec avails  `thenRn` \ (filtered_avails, hides, explicits) ->
172
173     let
174         unqual_imp = not qual_only              -- Maybe want unqualified names
175         qual_mod   = case as_mod of
176                         Nothing           -> imp_mod_name
177                         Just another_name -> another_name
178
179         mk_prov name = NonLocalDef (UserImport imp_mod iloc (name `elemNameSet` explicits)) 
180         gbl_env      = mkGlobalRdrEnv qual_mod unqual_imp True hides mk_prov filtered_avails deprecs
181         exports      = mkExportAvails qual_mod unqual_imp gbl_env            filtered_avails
182     in
183     returnRn (gbl_env, exports)
184 \end{code}
185
186
187 \begin{code}
188 importsFromLocalDecls this_mod decls
189   = mapRn (getLocalDeclBinders this_mod) decls  `thenRn` \ avails_s ->
190         -- The avails that are returned don't include the "system" names
191     let
192         avails = concat avails_s
193
194         all_names :: [Name]     -- All the defns; no dups eliminated
195         all_names = [name | avail <- avails, name <- availNames avail]
196
197         dups :: [[Name]]
198         (_, dups) = removeDups compare all_names
199     in
200         -- Check for duplicate definitions
201     mapRn_ (addErrRn . dupDeclErr) dups                 `thenRn_` 
202
203
204         -- Record that locally-defined things are available
205     recordLocalSlurps (availsToNameSet avails)          `thenRn_`
206     let
207         mod_name   = moduleName this_mod
208         unqual_imp = True       -- Want unqualified names
209         mk_prov n  = LocalDef   -- Provenance is local
210         hides      = []         -- Hide nothing
211
212         gbl_env    = mkGlobalRdrEnv mod_name unqual_imp True hides mk_prov avails NoDeprecs
213             -- NoDeprecs: don't complain about locally defined names
214             -- For a start, we may be exporting a deprecated thing
215             -- Also we may use a deprecated thing in the defn of another
216             -- deprecated things.  We may even use a deprecated thing in
217             -- the defn of a non-deprecated thing, when changing a module's 
218             -- interface
219
220         exports    = mkExportAvails mod_name unqual_imp gbl_env            avails
221     in
222     returnRn (gbl_env, exports)
223
224 ---------------------------
225 getLocalDeclBinders :: Module -> RdrNameHsDecl -> RnMG [AvailInfo]
226 getLocalDeclBinders mod (TyClD tycl_decl)
227   =     -- For type and class decls, we generate Global names, with
228         -- no export indicator.  They need to be global because they get
229         -- permanently bound into the TyCons and Classes.  They don't need
230         -- an export indicator because they are all implicitly exported.
231     getTyClDeclBinders mod tycl_decl    `thenRn` \ (avail, sys_names) ->
232
233         -- Record that the system names are available
234     recordLocalSlurps (mkNameSet sys_names)     `thenRn_`
235     returnRn [avail]
236
237 getLocalDeclBinders mod (ValD binds)
238   = mapRn new (collectLocatedHsBinders binds)           `thenRn` \ avails ->
239     returnRn avails
240   where
241     new (rdr_name, loc) = newTopBinder mod rdr_name loc         `thenRn` \ name ->
242                           returnRn (Avail name)
243
244 getLocalDeclBinders mod (ForD (ForeignDecl nm kind _ ext_nm _ loc))
245   | binds_haskell_name kind
246   = newTopBinder mod nm loc         `thenRn` \ name ->
247     returnRn [Avail name]
248
249   | otherwise           -- a foreign export
250   = returnRn []
251   where
252     binds_haskell_name (FoImport _) = True
253     binds_haskell_name FoLabel      = True
254     binds_haskell_name FoExport     = isDynamicExtName ext_nm
255
256 getLocalDeclBinders mod (FixD _)    = returnRn []
257 getLocalDeclBinders mod (DeprecD _) = returnRn []
258 getLocalDeclBinders mod (DefD _)    = returnRn []
259 getLocalDeclBinders mod (InstD _)   = returnRn []
260 getLocalDeclBinders mod (RuleD _)   = returnRn []
261 \end{code}
262
263
264 %************************************************************************
265 %*                                                                      *
266 \subsection{Filtering imports}
267 %*                                                                      *
268 %************************************************************************
269
270 @filterImports@ takes the @ExportEnv@ telling what the imported module makes
271 available, and filters it through the import spec (if any).
272
273 \begin{code}
274 filterImports :: ModuleName                     -- The module being imported
275               -> WhereFrom                      -- Tells whether it's a {-# SOURCE #-} import
276               -> Maybe (Bool, [RdrNameIE])      -- Import spec; True => hiding
277               -> [AvailInfo]                    -- What's available
278               -> RnMG ([AvailInfo],             -- What's actually imported
279                        [AvailInfo],             -- What's to be hidden
280                                                 -- (the unqualified version, that is)
281                         -- (We need to return both the above sets, because
282                         --  the qualified version is never hidden; so we can't
283                         --  implement hiding by reducing what's imported.)
284                        NameSet)                 -- What was imported explicitly
285
286         -- Complains if import spec mentions things that the module doesn't export
287         -- Warns/informs if import spec contains duplicates.
288 filterImports mod from Nothing imports
289   = returnRn (imports, [], emptyNameSet)
290
291 filterImports mod from (Just (want_hiding, import_items)) total_avails
292   = flatMapRn get_item import_items             `thenRn` \ avails_w_explicits ->
293     let
294         (item_avails, explicits_s) = unzip avails_w_explicits
295         explicits                  = foldl addListToNameSet emptyNameSet explicits_s
296     in
297     if want_hiding 
298     then        
299         -- All imported; item_avails to be hidden
300         returnRn (total_avails, item_avails, emptyNameSet)
301     else
302         -- Just item_avails imported; nothing to be hidden
303         returnRn (item_avails, [], explicits)
304   where
305     import_fm :: FiniteMap OccName AvailInfo
306     import_fm = listToFM [ (nameOccName name, avail) 
307                          | avail <- total_avails,
308                            name  <- availNames avail]
309         -- Even though availNames returns data constructors too,
310         -- they won't make any difference because naked entities like T
311         -- in an import list map to TcOccs, not VarOccs.
312
313     bale_out item = addErrRn (badImportItemErr mod from item)   `thenRn_`
314                     returnRn []
315
316     get_item item@(IEModuleContents _) = bale_out item
317
318     get_item item@(IEThingAll _)
319       = case check_item item of
320           Nothing                    -> bale_out item
321           Just avail@(AvailTC _ [n]) ->         -- This occurs when you import T(..), but
322                                                 -- only export T abstractly.  The single [n]
323                                                 -- in the AvailTC is the type or class itself
324                                         addWarnRn (dodgyImportWarn mod item)    `thenRn_`
325                                         returnRn [(avail, [availName avail])]
326           Just avail                 -> returnRn [(avail, [availName avail])]
327
328     get_item item@(IEThingAbs n)
329       | want_hiding     -- hiding( C ) 
330                         -- Here the 'C' can be a data constructor *or* a type/class
331       = case catMaybes [check_item item, check_item (IEThingAbs data_n)] of
332                 []     -> bale_out item
333                 avails -> returnRn [(a, []) | a <- avails]
334                                 -- The 'explicits' list is irrelevant when hiding
335       where
336         data_n = setRdrNameOcc n (setOccNameSpace (rdrNameOcc n) dataName)
337
338     get_item item
339       = case check_item item of
340           Nothing    -> bale_out item
341           Just avail -> returnRn [(avail, availNames avail)]
342
343     check_item item
344       | not (maybeToBool maybe_in_import_avails) ||
345         not (maybeToBool maybe_filtered_avail)
346       = Nothing
347
348       | otherwise    
349       = Just filtered_avail
350                 
351       where
352         wanted_occ             = rdrNameOcc (ieName item)
353         maybe_in_import_avails = lookupFM import_fm wanted_occ
354
355         Just avail             = maybe_in_import_avails
356         maybe_filtered_avail   = filterAvail item avail
357         Just filtered_avail    = maybe_filtered_avail
358 \end{code}
359
360
361
362 %************************************************************************
363 %*                                                                      *
364 \subsection{Qualifiying imports}
365 %*                                                                      *
366 %************************************************************************
367
368 \begin{code}
369 mkEmptyExportAvails :: ModuleName -> ExportAvails
370 mkEmptyExportAvails mod_name = (unitFM mod_name [], emptyUFM)
371
372 mkExportAvails :: ModuleName -> Bool -> GlobalRdrEnv -> [AvailInfo] -> ExportAvails
373 mkExportAvails mod_name unqual_imp gbl_env avails
374   = (mod_avail_env, entity_avail_env)
375   where
376     mod_avail_env = unitFM mod_name unqual_avails 
377
378         -- unqual_avails is the Avails that are visible in *unqualfied* form
379         -- (1.4 Report, Section 5.1.1)
380         -- For example, in 
381         --      import T hiding( f )
382         -- we delete f from avails
383
384     unqual_avails | not unqual_imp = [] -- Short cut when no unqualified imports
385                   | otherwise      = mapMaybe prune avails
386
387     prune (Avail n) | unqual_in_scope n = Just (Avail n)
388     prune (Avail n) | otherwise         = Nothing
389     prune (AvailTC n ns) | null uqs     = Nothing
390                          | otherwise    = Just (AvailTC n uqs)
391                          where
392                            uqs = filter unqual_in_scope ns
393
394     unqual_in_scope n = unQualInScope gbl_env n
395
396     entity_avail_env = listToUFM [ (name,avail) | avail <- avails, 
397                                                   name  <- availNames avail]
398
399 plusExportAvails ::  ExportAvails ->  ExportAvails ->  ExportAvails
400 plusExportAvails (m1, e1) (m2, e2)
401   = (plusFM_C (++) m1 m2, plusAvailEnv e1 e2)
402         -- ToDo: wasteful: we do this once for each constructor!
403 \end{code}
404
405
406 %************************************************************************
407 %*                                                                      *
408 \subsection{Export list processing}
409 %*                                                                      *
410 %************************************************************************
411
412 Processing the export list.
413
414 You might think that we should record things that appear in the export list
415 as ``occurrences'' (using @addOccurrenceName@), but you'd be wrong.
416 We do check (here) that they are in scope,
417 but there is no need to slurp in their actual declaration
418 (which is what @addOccurrenceName@ forces).
419
420 Indeed, doing so would big trouble when
421 compiling @PrelBase@, because it re-exports @GHC@, which includes @takeMVar#@,
422 whose type includes @ConcBase.StateAndSynchVar#@, and so on...
423
424 \begin{code}
425 type ExportAccum        -- The type of the accumulating parameter of
426                         -- the main worker function in exportsFromAvail
427      = ([ModuleName],           -- 'module M's seen so far
428         ExportOccMap,           -- Tracks exported occurrence names
429         AvailEnv)               -- The accumulated exported stuff, kept in an env
430                                 --   so we can common-up related AvailInfos
431
432 type ExportOccMap = FiniteMap OccName (Name, RdrNameIE)
433         -- Tracks what a particular exported OccName
434         --   in an export list refers to, and which item
435         --   it came from.  It's illegal to export two distinct things
436         --   that have the same occurrence name
437
438
439 exportsFromAvail :: ModuleName
440                  -> Maybe [RdrNameIE]   -- Export spec
441                  -> ExportAvails
442                  -> GlobalRdrEnv 
443                  -> RnMG Avails
444         -- Complains if two distinct exports have same OccName
445         -- Warns about identical exports.
446         -- Complains about exports items not in scope
447 exportsFromAvail this_mod Nothing export_avails global_name_env
448   = exportsFromAvail this_mod true_exports export_avails global_name_env
449   where
450     true_exports = Just $ if this_mod == mAIN_Name
451                           then [IEVar main_RDR_Unqual]
452                                -- export Main.main *only* unless otherwise specified,
453                           else [IEModuleContents this_mod]
454                                -- but for all other modules export everything.
455
456 exportsFromAvail this_mod (Just export_items) 
457                  (mod_avail_env, entity_avail_env)
458                  global_name_env
459   = doptRn Opt_WarnDuplicateExports             `thenRn` \ warn_dup_exports ->
460     foldlRn (exports_from_item warn_dup_exports)
461             ([], emptyFM, emptyAvailEnv) export_items
462                                                 `thenRn` \ (_, _, export_avail_map) ->
463     let
464         export_avails :: [AvailInfo]
465         export_avails   = nameEnvElts export_avail_map
466     in
467     returnRn export_avails
468
469   where
470     exports_from_item :: Bool -> ExportAccum -> RdrNameIE -> RnMG ExportAccum
471
472     exports_from_item warn_dups acc@(mods, occs, avails) ie@(IEModuleContents mod)
473         | mod `elem` mods       -- Duplicate export of M
474         = warnCheckRn warn_dups (dupModuleExport mod)   `thenRn_`
475           returnRn acc
476
477         | otherwise
478         = case lookupFM mod_avail_env mod of
479                 Nothing         -> failWithRn acc (modExportErr mod)
480                 Just mod_avails -> foldlRn (check_occs ie) occs mod_avails
481                                    `thenRn` \ occs' ->
482                                    let
483                                         avails' = foldl addAvail avails mod_avails
484                                    in
485                                    returnRn (mod:mods, occs', avails')
486
487     exports_from_item warn_dups acc@(mods, occs, avails) ie
488         = lookupSrcName global_name_env (ieName ie)     `thenRn` \ name -> 
489
490                 -- See what's available in the current environment
491           case lookupUFM entity_avail_env name of {
492             Nothing ->  -- Presumably this happens because lookupSrcName didn't find
493                         -- the name and returned an unboundName, which won't be in
494                         -- the entity_avail_env, of course
495                         WARN( not (isUnboundName name), ppr name )
496                         returnRn acc ;
497
498             Just avail ->
499
500                 -- Filter out the bits we want
501           case filterAvail ie avail of {
502             Nothing ->  -- Not enough availability
503                            failWithRn acc (exportItemErr ie) ;
504
505             Just export_avail ->        
506
507                 -- Phew!  It's OK!  Now to check the occurrence stuff!
508           warnCheckRn (ok_item ie avail) (dodgyExportWarn ie)   `thenRn_`
509           check_occs ie occs export_avail                       `thenRn` \ occs' ->
510           returnRn (mods, occs', addAvail avails export_avail)
511           }}
512
513
514
515 ok_item (IEThingAll _) (AvailTC _ [n]) = False
516   -- This occurs when you import T(..), but
517   -- only export T abstractly.  The single [n]
518   -- in the AvailTC is the type or class itself
519 ok_item _ _ = True
520
521 check_occs :: RdrNameIE -> ExportOccMap -> AvailInfo -> RnMG ExportOccMap
522 check_occs ie occs avail 
523   = doptRn Opt_WarnDuplicateExports     `thenRn` \ warn_dup_exports ->
524     foldlRn (check warn_dup_exports) occs (availNames avail)
525   where
526     check warn_dup occs name
527       = case lookupFM occs name_occ of
528           Nothing           -> returnRn (addToFM occs name_occ (name, ie))
529           Just (name', ie') 
530             | name == name' ->  -- Duplicate export
531                                 warnCheckRn warn_dup
532                                             (dupExportWarn name_occ ie ie')
533                                 `thenRn_` returnRn occs
534
535             | otherwise     ->  -- Same occ name but different names: an error
536                                 failWithRn occs (exportClashErr name_occ ie ie')
537       where
538         name_occ = nameOccName name
539 \end{code}
540
541 %************************************************************************
542 %*                                                                      *
543 \subsection{Errors}
544 %*                                                                      *
545 %************************************************************************
546
547 \begin{code}
548 badImportItemErr mod from ie
549   = sep [ptext SLIT("Module"), quotes (ppr mod), source_import,
550          ptext SLIT("does not export"), quotes (ppr ie)]
551   where
552     source_import = case from of
553                       ImportByUserSource -> ptext SLIT("(hi-boot interface)")
554                       other              -> empty
555
556 dodgyImportWarn mod item = dodgyMsg (ptext SLIT("import")) item
557 dodgyExportWarn     item = dodgyMsg (ptext SLIT("export")) item
558
559 dodgyMsg kind item@(IEThingAll tc)
560   = sep [ ptext SLIT("The") <+> kind <+> ptext SLIT("item") <+> quotes (ppr item),
561           ptext SLIT("suggests that") <+> quotes (ppr tc) <+> ptext SLIT("has constructor or class methods"),
562           ptext SLIT("but it has none; it is a type synonym or abstract type or class") ]
563           
564 modExportErr mod
565   = hsep [ ptext SLIT("Unknown module in export list: module"), quotes (ppr mod)]
566
567 exportItemErr export_item
568   = sep [ ptext SLIT("The export item") <+> quotes (ppr export_item),
569           ptext SLIT("attempts to export constructors or class methods that are not visible here") ]
570
571 exportClashErr occ_name ie1 ie2
572   = hsep [ptext SLIT("The export items"), quotes (ppr ie1)
573          ,ptext SLIT("and"), quotes (ppr ie2)
574          ,ptext SLIT("create conflicting exports for"), quotes (ppr occ_name)]
575
576 dupDeclErr (n:ns)
577   = vcat [ptext SLIT("Multiple declarations of") <+> quotes (ppr n),
578           nest 4 (vcat (map ppr sorted_locs))]
579   where
580     sorted_locs = sortLt occ'ed_before (map nameSrcLoc (n:ns))
581     occ'ed_before a b = LT == compare a b
582
583 dupExportWarn occ_name ie1 ie2
584   = hsep [quotes (ppr occ_name), 
585           ptext SLIT("is exported by"), quotes (ppr ie1),
586           ptext SLIT("and"),            quotes (ppr ie2)]
587
588 dupModuleExport mod
589   = hsep [ptext SLIT("Duplicate"),
590           quotes (ptext SLIT("Module") <+> ppr mod), 
591           ptext SLIT("in export list")]
592
593 moduleDeprec mod txt
594   = sep [ ptext SLIT("Module") <+> quotes (ppr mod) <+> ptext SLIT("is deprecated:"), 
595           nest 4 (ppr txt) ]      
596 \end{code}