[project @ 1997-11-29 20:33:18 by sof]
[ghc-hetmet.git] / ghc / compiler / rename / RnNames.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
3 %
4 \section[RnNames]{Extracting imported and top-level names in scope}
5
6 \begin{code}
7 #include "HsVersions.h"
8
9 module RnNames (
10         getGlobalNames
11     ) where
12
13 IMP_Ubiq()
14
15 import CmdLineOpts      ( opt_SourceUnchanged, opt_NoImplicitPrelude, 
16                           opt_WarnDuplicateExports
17                         )
18 import HsSyn    ( HsModule(..), HsDecl(..), FixityDecl(..), Fixity, Fake, InPat, IE(..), HsTyVar,
19                   TyDecl, ClassDecl, InstDecl, DefaultDecl, ImportDecl(..), HsBinds, IfaceSig,
20                   collectTopBinders
21                 )
22 import HsImpExp ( ieName )
23 import RdrHsSyn ( RdrNameHsDecl(..), RdrName(..), RdrNameIE(..), SYN_IE(RdrNameImportDecl),
24                   SYN_IE(RdrNameHsModule), SYN_IE(RdrNameFixityDecl),
25                   rdrNameOcc, ieOcc
26                 )
27 import RnHsSyn  ( RenamedHsModule(..), RenamedFixityDecl(..) )
28 import RnIfaces ( getInterfaceExports, getDeclBinders, checkUpToDate, recordSlurp )
29 import BasicTypes ( IfaceFlavour(..) )
30 import RnEnv
31 import RnMonad
32
33 import FiniteMap
34 import PrelMods
35 import UniqFM   ( UniqFM, emptyUFM, addListToUFM_C, lookupUFM )
36 import Bag      ( Bag, bagToList )
37 import Maybes   ( maybeToBool, expectJust )
38 import Name
39 import Pretty
40 import Outputable       ( Outputable(..), PprStyle(..) )
41 import Util     ( panic, pprTrace, assertPanic, removeDups, cmpPString )
42 \end{code}
43
44
45
46 %************************************************************************
47 %*                                                                      *
48 \subsection{Get global names}
49 %*                                                                      *
50 %************************************************************************
51
52 \begin{code}
53 getGlobalNames :: RdrNameHsModule
54                -> RnMG (Maybe (ExportEnv, RnEnv, NameSet))
55                         -- Nothing <=> no need to recompile
56                         -- The NameSet is the set of names that are
57                         --      either locally defined,
58                         --      or explicitly imported
59
60 getGlobalNames m@(HsModule this_mod _ exports imports _ _ mod_loc)
61   = fixRn (\ ~(rec_exp_fn, _) ->
62
63         -- PROCESS LOCAL DECLS
64         -- Do these *first* so that the correct provenance gets
65         -- into the global name cache.
66       importsFromLocalDecls rec_exp_fn m        `thenRn` \ (local_rn_env, local_mod_avails, local_avails) ->
67
68         -- PROCESS IMPORT DECLS
69       mapAndUnzip3Rn importsFromImportDecl all_imports
70                                                 `thenRn` \ (imp_rn_envs, imp_avails_s, explicit_imports_s) ->
71
72         -- CHECK FOR EARLY EXIT
73       checkEarlyExit this_mod                   `thenRn` \ early_exit ->
74       if early_exit then
75                 returnRn (junk_exp_fn, Nothing)
76       else
77
78         -- COMBINE RESULTS
79         -- We put the local env second, so that a local provenance
80         -- "wins", even if a module imports itself.
81       foldlRn plusRnEnv emptyRnEnv imp_rn_envs          `thenRn` \ imp_rn_env ->
82       plusRnEnv imp_rn_env local_rn_env                 `thenRn` \ rn_env ->
83       let
84          export_avails :: ExportAvails
85          export_avails = foldr plusExportAvails local_mod_avails imp_avails_s
86
87          explicit_names :: NameSet      -- locally defined or explicitly imported
88          explicit_names = foldr add_on emptyNameSet (local_avails : explicit_imports_s)
89          add_on avails names = foldr (unionNameSets . mkNameSet . availNames) names avails
90       in
91   
92         -- PROCESS EXPORT LISTS
93       exportsFromAvail this_mod exports export_avails rn_env    
94                                                         `thenRn` \ (export_fn, export_env) ->
95
96         -- RECORD THAT LOCALLY DEFINED THINGS ARE AVAILABLE
97       mapRn (recordSlurp Nothing Compulsory) local_avails       `thenRn_`
98
99       returnRn (export_fn, Just (export_env, rn_env, explicit_names))
100     )                                                   `thenRn` \ (_, result) ->
101     returnRn result
102   where
103     junk_exp_fn = error "RnNames:export_fn"
104
105     all_imports = prel_imports ++ imports
106
107         -- NB: opt_NoImplicitPrelude is slightly different to import Prelude ();
108         -- because the former doesn't even look at Prelude.hi for instance declarations,
109         -- whereas the latter does.
110     prel_imports | this_mod == pRELUDE ||
111                    explicit_prelude_import ||
112                    opt_NoImplicitPrelude
113                  = []
114
115                  | otherwise               = [ImportDecl pRELUDE 
116                                                          False          {- Not qualified -}
117                                                          HiFile         {- Not source imported -}
118                                                          Nothing        {- No "as" -}
119                                                          Nothing        {- No import list -}
120                                                          mod_loc]
121     
122     explicit_prelude_import
123       = not (null [ () | (ImportDecl mod qual _ _ _ _) <- imports, mod == pRELUDE ])
124 \end{code}
125         
126 \begin{code}
127 checkEarlyExit mod
128   = checkErrsRn                         `thenRn` \ no_errs_so_far ->
129     if not no_errs_so_far then
130         -- Found errors already, so exit now
131         returnRn True
132     else
133     traceRn (text "Considering whether compilation is required...")     `thenRn_`
134     if not opt_SourceUnchanged then
135         -- Source code changed and no errors yet... carry on 
136         traceRn (nest 4 (text "source file changed or recompilation check turned off")) `thenRn_` 
137         returnRn False
138     else
139         -- Unchanged source, and no errors yet; see if usage info
140         -- up to date, and exit if so
141         checkUpToDate mod                                               `thenRn` \ up_to_date ->
142         putDocRn (text "Compilation" <+> 
143                   text (if up_to_date then "IS NOT" else "IS") <+>
144                   text "required")                                      `thenRn_`
145         returnRn up_to_date
146 \end{code}
147         
148
149 \begin{code}
150 importsFromImportDecl :: RdrNameImportDecl
151                       -> RnMG (RnEnv, ExportAvails, [AvailInfo])
152
153 importsFromImportDecl (ImportDecl mod qual_only as_source as_mod import_spec loc)
154   = pushSrcLocRn loc $
155     getInterfaceExports mod as_source           `thenRn` \ (avails, fixities) ->
156     filterImports mod import_spec avails        `thenRn` \ (filtered_avails, hides, explicits) ->
157     let
158         filtered_avails' = map set_avail_prov filtered_avails
159         fixities'        = [ (occ,(fixity,provenance)) | (occ,fixity) <- fixities ]
160     in
161     qualifyImports mod 
162                    True                 -- Want qualified names
163                    (not qual_only)      -- Maybe want unqualified names
164                    as_mod
165                    (ExportEnv filtered_avails' fixities')
166                    hides
167                                                         `thenRn` \ (rn_env, mod_avails) ->
168     returnRn (rn_env, mod_avails, explicits)
169   where
170     set_avail_prov NotAvailable   = NotAvailable
171     set_avail_prov (Avail n)      = Avail (set_name_prov n) 
172     set_avail_prov (AvailTC n ns) = AvailTC (set_name_prov n) (map set_name_prov ns)
173     set_name_prov name | isWiredInName name = name
174                        | otherwise          = setNameProvenance name provenance
175     provenance = Imported mod loc as_source
176 \end{code}
177
178
179 \begin{code}
180 importsFromLocalDecls rec_exp_fn (HsModule mod _ _ _ fix_decls decls _)
181   = foldlRn getLocalDeclBinders [] decls                `thenRn` \ avails ->
182     mapRn fixityFromFixDecl fix_decls                   `thenRn` \ fixities ->
183     qualifyImports mod 
184                    False        -- Don't want qualified names
185                    True         -- Want unqualified names
186                    Nothing      -- No "as M" part
187                    (ExportEnv avails fixities)
188                    []           -- Hide nothing
189                                                         `thenRn` \ (rn_env, mod_avails) ->
190     returnRn (rn_env, mod_avails, avails)
191   where
192     newLocalName rdr_name loc
193       = newLocallyDefinedGlobalName mod (rdrNameOcc rdr_name) rec_exp_fn loc
194
195     getLocalDeclBinders avails (ValD binds)
196       = mapRn do_one (bagToList (collectTopBinders binds))      `thenRn` \ val_avails ->
197         returnRn (val_avails ++ avails)
198
199     getLocalDeclBinders avails decl
200       = getDeclBinders newLocalName decl        `thenRn` \ avail ->
201         case avail of
202            NotAvailable -> returnRn avails              -- Instance decls and suchlike
203            other        -> returnRn (avail : avails)
204
205     do_one (rdr_name, loc)
206       = newLocalName rdr_name loc       `thenRn` \ name ->
207         returnRn (Avail name)
208 \end{code}
209
210 %************************************************************************
211 %*                                                                      *
212 \subsection{Filtering imports}
213 %*                                                                      *
214 %************************************************************************
215
216 @filterImports@ takes the @ExportEnv@ telling what the imported module makes
217 available, and filters it through the import spec (if any).
218
219 \begin{code}
220 filterImports :: Module
221               -> Maybe (Bool, [RdrNameIE])              -- Import spec; True => hidin
222               -> [AvailInfo]                            -- What's available
223               -> RnMG ([AvailInfo],                     -- What's actually imported
224                        [AvailInfo],                     -- What's to be hidden (the unqualified version, that is)
225                        [AvailInfo])                     -- What was imported explicitly
226
227         -- Complains if import spec mentions things that the module doesn't export
228         -- Warns/informs if import spec contains duplicates.
229 filterImports mod Nothing imports
230   = returnRn (imports, [], [])
231
232 filterImports mod (Just (want_hiding, import_items)) avails
233   = mapRn check_item import_items               `thenRn` \ item_avails ->
234     if want_hiding 
235     then        
236         returnRn (avails, item_avails, [])      -- All imported; item_avails to be hidden
237     else
238         returnRn (item_avails, [], item_avails) -- Just item_avails imported; nothing to be hidden
239
240   where
241     import_fm :: FiniteMap OccName AvailInfo
242     import_fm = listToFM [ (nameOccName name, avail) 
243                          | avail <- avails,
244                            name  <- availEntityNames avail]
245
246     check_item item@(IEModuleContents _)
247       = addErrRn (badImportItemErr mod item)    `thenRn_`
248         returnRn NotAvailable
249
250     check_item item
251       | not (maybeToBool maybe_in_import_avails) ||
252         (case filtered_avail of { NotAvailable -> True; other -> False })
253       = addErrRn (badImportItemErr mod item)    `thenRn_`
254         returnRn NotAvailable
255
256       | otherwise   = returnRn filtered_avail
257                 
258       where
259         maybe_in_import_avails = lookupFM import_fm (ieOcc item)
260         Just avail             = maybe_in_import_avails
261         filtered_avail         = filterAvail item avail
262 \end{code}
263
264
265
266 %************************************************************************
267 %*                                                                      *
268 \subsection{Qualifiying imports}
269 %*                                                                      *
270 %************************************************************************
271
272 @qualifyImports@ takes the @ExportEnv@ after filtering through the import spec
273 of an import decl, and deals with producing an @RnEnv@ with the 
274 right qualified names.  It also turns the @Names@ in the @ExportEnv@ into
275 fully fledged @Names@.
276
277 \begin{code}
278 qualifyImports :: Module                                -- Imported module
279                -> Bool                                  -- True <=> want qualified import
280                -> Bool                                  -- True <=> want unqualified import
281                -> Maybe Module                          -- Optional "as M" part 
282                -> ExportEnv                             -- What's imported
283                -> [AvailInfo]                           -- What's to be hidden
284                -> RnMG (RnEnv, ExportAvails)
285
286 qualifyImports this_mod qual_imp unqual_imp as_mod (ExportEnv avails fixities) hides
287   = 
288         -- Make the name environment.  Even though we're talking about a 
289         -- single import module there might still be name clashes, 
290         -- because it might be the module being compiled.
291     foldlRn add_avail emptyNameEnv avails       `thenRn` \ name_env1 ->
292     let
293         -- Delete things that are hidden
294         name_env2 = foldl del_avail name_env1 hides
295
296         -- Create the fixity env
297         fixity_env = foldl (add_fixity name_env2) emptyFixityEnv fixities
298
299         -- Create the export-availability info
300         export_avails = mkExportAvails unqual_imp qual_mod avails
301     in
302     returnRn (RnEnv name_env2 fixity_env, export_avails)
303   where
304     qual_mod = case as_mod of
305                   Nothing           -> this_mod
306                   Just another_name -> another_name
307
308     add_avail env avail = foldlRn add_name env (availNames avail)
309     add_name env name   = add qual_imp   env  (Qual qual_mod occ err_hif) `thenRn` \ env1 ->
310                           add unqual_imp env1 (Unqual occ)
311                         where
312                           add False env rdr_name = returnRn env
313                           add True  env rdr_name = addOneToNameEnv env rdr_name name
314                           occ  = nameOccName name
315
316     del_avail env avail = foldl delOneFromNameEnv env rdr_names
317                         where
318                           rdr_names = map (Unqual . nameOccName) (availNames avail)
319                         
320     add_fixity name_env fix_env (occ_name, (fixity, provenance))
321         = add qual $ add unqual $ fix_env
322         where
323           qual   = Qual qual_mod occ_name err_hif
324           unqual = Unqual occ_name
325
326           add rdr_name fix_env | maybeToBool (lookupFM name_env rdr_name)
327                                = addOneToFixityEnv fix_env rdr_name (fixity,provenance)
328                                | otherwise
329                                = fix_env
330
331 err_hif = error "qualifyImports: hif"   -- Not needed in key to mapping
332 \end{code}
333
334 unQualify adds an Unqual binding for every existing Qual binding.
335
336 \begin{code}
337 unQualify :: FiniteMap RdrName elt -> FiniteMap RdrName elt
338 unQualify fm = addListToFM fm [(Unqual occ, elt) | (Qual _ occ _, elt) <- fmToList fm]
339 \end{code}
340
341 %************************************************************************
342 %*                                                                      *
343 \subsection{Local declarations}
344 %*                                                                      *
345 %************************************************************************
346
347
348 \begin{code}
349 fixityFromFixDecl :: RdrNameFixityDecl -> RnMG (OccName, (Fixity, Provenance))
350
351 fixityFromFixDecl (FixityDecl rdr_name fixity loc)
352   = returnRn (rdrNameOcc rdr_name, (fixity, LocalDef (panic "export-flag") loc))
353 \end{code}
354
355
356 %************************************************************************
357 %*                                                                      *
358 \subsection{Export list processing
359 %*                                                                      *
360 %************************************************************************
361
362 The @AvailEnv@ type is just used internally in @exportsFromAvail@.
363 When exporting we need to combine the availabilities for a particular
364 exported thing, and we also need to check for name clashes -- that
365 is: two exported things must have different @OccNames@.
366
367 \begin{code}
368 type AvailEnv = FiniteMap OccName (RdrNameIE, AvailInfo, Int{-no. of clashes-})
369         -- The FM maps each OccName to the RdrNameIE that gave rise to it,
370         -- for error reporting, as well as to its AvailInfo
371
372 emptyAvailEnv = emptyFM
373
374 {-
375  Add new entry to environment. Checks for name clashes, i.e.,
376  plain duplicates or exported entity pairs that have different OccNames.
377  (c.f. 5.1.1 of Haskell 1.4 report.)
378 -}
379 addAvailEnv :: Bool -> RdrNameIE -> AvailEnv -> AvailInfo -> RnM s d AvailEnv
380 addAvailEnv warn_dups ie env NotAvailable   = returnRn env
381 addAvailEnv warn_dups ie env (AvailTC _ []) = returnRn env
382 addAvailEnv warn_dups ie env avail
383   | warn_dups = mapMaybeRn (addErrRn  . availClashErr) () conflict `thenRn_`
384                 returnRn (addToFM_C add_avail env key elt)
385   | otherwise = returnRn (addToFM_C add_avail env key elt)
386   where
387    key  = nameOccName (availName avail)
388    elt  = (ie,avail,reports_on)
389
390    reports_on
391     | maybeToBool dup = 1
392     | otherwise       = 0
393
394    conflict = conflictFM bad_avail env key elt
395    dup 
396     | warn_dups = conflictFM dup_avail env key elt
397     | otherwise = Nothing
398
399 addListToAvailEnv :: AvailEnv -> RdrNameIE -> [AvailInfo] -> RnM s d AvailEnv
400 addListToAvailEnv env ie items = foldlRn (addAvailEnv False ie) env items
401
402 bad_avail  (ie1,avail1,r1) (ie2,avail2,r2) 
403    = availName avail1 /= availName avail2  -- Same OccName, different Name
404 dup_avail  (ie1,avail1,r1) (ie2,avail2,r2) 
405    = availName avail1 == availName avail2 -- Same OccName & avail.
406
407 add_avail (ie1,a1,r1) (ie2,a2,r2) = (ie1, a1 `plusAvail` a2, r1 + r2)
408
409 \end{code}
410
411 Processing the export list.
412
413 You might think that we should record things that appear in the export list as
414 ``occurrences'' (using addOccurrenceName), but you'd be wrong.  We do check (here)
415 that they are in scope, but there is no need to slurp in their actual declaration
416 (which is what addOccurrenceName forces).  Indeed, doing so would big trouble when
417 compiling PrelBase, because it re-exports GHC, which includes takeMVar#, whose type
418 includes ConcBase.StateAndSynchVar#, and so on...
419
420 \begin{code}
421 exportsFromAvail :: Module
422                  -> Maybe [RdrNameIE]   -- Export spec
423                  -> ExportAvails
424                  -> RnEnv
425                  -> RnMG (Name -> ExportFlag, ExportEnv)
426         -- Complains if two distinct exports have same OccName
427         -- Warns about identical exports.
428         -- Complains about exports items not in scope
429 exportsFromAvail this_mod Nothing export_avails rn_env
430   = exportsFromAvail this_mod (Just [IEModuleContents this_mod]) export_avails rn_env
431
432 exportsFromAvail this_mod (Just export_items) 
433                  (mod_avail_env, entity_avail_env)
434                  (RnEnv name_env fixity_env)
435   = checkForModuleExportDups export_items                 `thenRn` \ export_items' ->
436     foldlRn exports_from_item emptyAvailEnv export_items' `thenRn` \ export_avail_env ->
437     let
438      dup_entries = fmToList (filterFM (\ _ (_,_,clashes) -> clashes > 0) export_avail_env)
439     in
440     mapRn (addWarnRn . dupExportWarn) dup_entries         `thenRn_`
441     let
442         export_avails   = map (\ (_,a,_) -> a) (eltsFM export_avail_env)
443         export_fixities = mk_exported_fixities (availsToNameSet export_avails)
444         export_fn       = mk_export_fn export_avails
445     in
446     returnRn (export_fn, ExportEnv export_avails export_fixities)
447
448   where
449     exports_from_item :: AvailEnv -> RdrNameIE -> RnMG AvailEnv
450     exports_from_item export_avail_env ie@(IEModuleContents mod)
451         = case lookupFM mod_avail_env mod of
452                 Nothing     -> failWithRn export_avail_env (modExportErr mod)
453                 Just avails -> addListToAvailEnv export_avail_env ie avails
454
455     exports_from_item export_avail_env ie
456         | not (maybeToBool maybe_in_scope) 
457         = failWithRn export_avail_env (unknownNameErr (ieName ie))
458
459 #ifdef DEBUG
460         -- I can't see why this should ever happen; if the thing is in scope
461         -- at all it ought to have some availability
462         | not (maybeToBool maybe_avail)
463         = pprTrace "exportsFromAvail: curious Nothing:" (ppr PprDebug name)
464           returnRn export_avail_env
465 #endif
466
467         | not enough_avail
468         = failWithRn export_avail_env (exportItemErr ie export_avail)
469
470         | otherwise     -- Phew!  It's OK!
471         = addAvailEnv opt_WarnDuplicateExports ie export_avail_env export_avail
472        where
473           maybe_in_scope  = lookupNameEnv name_env (ieName ie)
474           Just name       = maybe_in_scope
475           maybe_avail     = lookupUFM entity_avail_env name
476           Just avail      = maybe_avail
477           export_avail    = filterAvail ie avail
478           enough_avail    = case export_avail of {NotAvailable -> False; other -> True}
479
480         -- We export a fixity iff we export a thing with the same (qualified) RdrName
481     mk_exported_fixities :: NameSet -> [(OccName, (Fixity, Provenance))]
482     mk_exported_fixities exports
483         = fmToList (foldr (perhaps_add_fixity exports) 
484                           emptyFM
485                           (fmToList fixity_env))
486
487     perhaps_add_fixity :: NameSet -> (RdrName, (Fixity, Provenance))
488                        -> FiniteMap OccName (Fixity,Provenance)
489                        -> FiniteMap OccName (Fixity,Provenance)
490     perhaps_add_fixity exports (rdr_name, (fixity, prov)) fix_env
491       =  let
492             do_nothing = fix_env                -- The default is to pass on the env unchanged
493          in
494                 -- Step 1: check whether the rdr_name is in scope; if so find its Name
495          case lookupFM name_env rdr_name of {
496            Nothing          -> do_nothing;
497            Just fixity_name -> 
498
499                 -- Step 2: check whether the fixity thing is exported
500          if not (fixity_name `elemNameSet` exports) then
501                 do_nothing
502          else
503         
504                 -- Step 3: check whether we already have a fixity for the
505                 -- Name's OccName in the fix_env we are building up.  This can easily
506                 -- happen.  the original fixity_env might contain bindings for
507                 --      M.a and N.a, if a was imported via M and N.
508                 -- If this does happen, we expect the fixity to be the same either way.
509         let
510             occ_name = rdrNameOcc rdr_name
511         in
512         case lookupFM fix_env occ_name of {
513           Just (fixity1, prov1) ->      -- Got it already
514                                    ASSERT( fixity == fixity1 )
515                                    do_nothing;
516           Nothing -> 
517
518                 -- Step 3: add it to the outgoing fix_env
519         addToFM fix_env occ_name (fixity,prov)
520         }}
521
522 {- warn and weed out duplicate module entries from export list. -}
523 checkForModuleExportDups :: [RdrNameIE] -> RnMG [RdrNameIE]
524 checkForModuleExportDups ls 
525   | opt_WarnDuplicateExports = check_modules ls
526   | otherwise                = returnRn ls
527   where
528    -- NOTE: reorders the export list by moving all module-contents
529    -- exports to the end (removing duplicates in the process.)
530    check_modules ls = 
531      (case dups of
532         [] -> returnRn ()
533         ls -> mapRn (\ ds@(IEModuleContents x:_) -> 
534                        addWarnRn (dupModuleExport x (length ds))) ls `thenRn_`
535               returnRn ()) `thenRn_`
536      returnRn (ls_no_modules ++ no_module_dups)
537      where
538       (ls_no_modules,modules) = foldr split_mods ([],[]) ls
539
540       split_mods i@(IEModuleContents _) ~(no_ms,ms) = (no_ms,i:ms)
541       split_mods i ~(no_ms,ms) = (i:no_ms,ms)
542
543       (no_module_dups, dups) = removeDups cmp_mods modules
544
545       cmp_mods (IEModuleContents m1) (IEModuleContents m2) = m1 `cmpPString` m2
546   
547 mk_export_fn :: [AvailInfo] -> (Name -> ExportFlag)
548 mk_export_fn avails
549   = \name -> if name `elemNameSet` exported_names
550              then Exported
551              else NotExported
552   where
553     exported_names :: NameSet
554     exported_names = availsToNameSet avails
555 \end{code}
556
557 %************************************************************************
558 %*                                                                      *
559 \subsection{Errors}
560 %*                                                                      *
561 %************************************************************************
562
563 \begin{code}
564 badImportItemErr mod ie sty
565   = sep [ptext SLIT("Module"), pprModule sty mod, ptext SLIT("does not export"), ppr sty ie]
566
567 modExportErr mod sty
568   = hsep [ ptext SLIT("Unknown module in export list: module"), ptext mod]
569
570 exportItemErr export_item NotAvailable sty
571   = sep [ ptext SLIT("Export item not in scope:"), ppr sty export_item ]
572
573 exportItemErr export_item avail sty
574   = hang (ptext SLIT("Export item not fully in scope:"))
575            4 (vcat [hsep [ptext SLIT("Wanted:   "), ppr sty export_item],
576                     hsep [ptext SLIT("Available:"), ppr sty (ieOcc export_item), pprAvail sty avail]])
577
578 availClashErr (occ_name, ((ie1,avail1,_), (ie2,avail2,_))) sty
579   = hsep [ptext SLIT("The export items"), ppr sty ie1, ptext SLIT("and"), ppr sty ie2,
580           ptext SLIT("create conflicting exports for"), ppr sty occ_name]
581
582 dupExportWarn (occ_name, (_,_,times)) sty
583   = hsep [ppr sty occ_name, 
584           ptext SLIT("mentioned"), text (speak_times (times+1)),
585           ptext SLIT("in export list")]
586
587 dupModuleExport mod times sty
588   = hsep [ptext SLIT("Module"), pprModule sty mod, 
589           ptext SLIT("mentioned"), text (speak_times times),
590           ptext SLIT("in export list")]
591
592 speak_times :: Int{- >=1 -} -> String
593 speak_times t | t == 1 = "once"
594               | t == 2 = "twice"
595               | otherwise  = show t ++ " times"
596
597
598 \end{code}
599