[project @ 1999-12-06 11:54:56 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / Rename.lhs
index bfb55af..730f02d 100644 (file)
@@ -22,16 +22,17 @@ import RnMonad
 import RnNames         ( getGlobalNames )
 import RnSource                ( rnSourceDecls, rnDecl )
 import RnIfaces                ( getImportedInstDecls, importDecl, getImportVersions,
-                         getImportedRules, loadHomeInterface, getSlurped
+                         getImportedRules, loadHomeInterface, getSlurped, removeContext
                        )
 import RnEnv           ( availName, availNames, availsToNameSet, 
-                         warnUnusedTopNames, mapFvRn,
+                         warnUnusedTopNames, mapFvRn, lookupImplicitOccRn,
                          FreeVars, plusFVs, plusFV, unitFV, emptyFVs, isEmptyFVs
                        )
 import Module           ( Module, ModuleName, pprModule, mkSearchPath, mkThisModule )
 import Name            ( Name, isLocallyDefined,
                          NamedThing(..), ImportReason(..), Provenance(..),
-                         pprOccName, getNameProvenance, 
+                         pprOccName, nameOccName,
+                         getNameProvenance, 
                          maybeWiredInTyConName, maybeWiredInIdName, isWiredInName
                        )
 import Id              ( idType )
@@ -41,15 +42,14 @@ import RdrName              ( RdrName )
 import NameSet
 import PrelMods                ( mAIN_Name, pREL_MAIN_Name )
 import TysWiredIn      ( unitTyCon, intTyCon, doubleTyCon, boolTyCon )
-import PrelInfo                ( ioTyCon_NAME, thinAirIdNames )
+import PrelInfo                ( ioTyCon_NAME, numClass_RDR, thinAirIdNames, derivingOccurrences )
 import Type            ( namesOfType, funTyCon )
-import ErrUtils                ( pprBagOfErrors, pprBagOfWarnings,
-                         doIfSet, dumpIfSet, ghcExit
-                       )
+import ErrUtils                ( printErrorsAndWarnings, dumpIfSet, ghcExit )
 import BasicTypes      ( NewOrData(..) )
 import Bag             ( isEmptyBag, bagToList )
 import FiniteMap       ( fmToList, delListFromFM, addToFM, sizeFM, eltsFM )
 import UniqSupply      ( UniqSupply )
+import UniqFM          ( lookupUFM )
 import Util            ( equivClasses )
 import Maybes          ( maybeToBool )
 import Outputable
@@ -72,28 +72,19 @@ renameModule us this_mod@(HsModule mod_name vers exports imports local_decls loc
   =    -- Initialise the renamer monad
     initRn mod_name us (mkSearchPath opt_HiMap) loc
           (rename this_mod)                            >>=
-       \ (maybe_rn_stuff, rn_errs_bag, rn_warns_bag) ->
+       \ ((maybe_rn_stuff, dump_action), rn_errs_bag, rn_warns_bag) ->
 
        -- Check for warnings
-    doIfSet (not (isEmptyBag rn_warns_bag))
-           (printErrs (pprBagOfWarnings rn_warns_bag)) >>
-
-       -- Check for errors; exit if so
-    doIfSet (not (isEmptyBag rn_errs_bag))
-           (printErrs (pprBagOfErrors rn_errs_bag)      >>
-            ghcExit 1
-           )                                            >>
-
-       -- Dump output, if any
-    (case maybe_rn_stuff of
-       Nothing  -> return ()
-       Just results@(_, rn_mod, _, _, _)
-                -> dumpIfSet opt_D_dump_rn "Renamer:"
-                             (ppr rn_mod)
-    )                                                  >>
+    printErrorsAndWarnings rn_errs_bag rn_warns_bag    >>
+
+       -- Dump any debugging output
+    dump_action                                        >>
 
        -- Return results
-    return maybe_rn_stuff
+    if not (isEmptyBag rn_errs_bag) then
+           ghcExit 1 >> return Nothing
+    else
+           return maybe_rn_stuff
 \end{code}
 
 
@@ -105,8 +96,8 @@ rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
        -- CHECK FOR EARLY EXIT
     if not (maybeToBool maybe_stuff) then
        -- Everything is up to date; no need to recompile further
-       rnStats []              `thenRn_`
-       returnRn Nothing
+       rnDump [] []            `thenRn` \ dump_action ->
+       returnRn (Nothing, dump_action)
     else
     let
        Just (export_env, gbl_env, fixity_env, global_avail_env) = maybe_stuff
@@ -118,20 +109,24 @@ rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
     )                                  `thenRn` \ (rn_local_decls, source_fvs) ->
 
        -- SLURP IN ALL THE NEEDED DECLARATIONS
+    implicitFVs mod_name rn_local_decls        `thenRn` \ implicit_fvs -> 
     let
-       real_source_fvs = implicitFVs mod_name `plusFV` source_fvs
+       real_source_fvs = implicit_fvs `plusFV` source_fvs
                -- It's important to do the "plus" this way round, so that
                -- when compiling the prelude, locally-defined (), Bool, etc
                -- override the implicit ones. 
     in
     slurpImpDecls real_source_fvs      `thenRn` \ rn_imp_decls ->
+    let
+       rn_all_decls       = rn_imp_decls ++ rn_local_decls 
+    in
 
        -- EXIT IF ERRORS FOUND
-    checkErrsRn                                `thenRn` \ no_errs_so_far ->
+    checkErrsRn                                        `thenRn` \ no_errs_so_far ->
     if not no_errs_so_far then
        -- Found errors already, so exit now
-       rnStats []              `thenRn_`
-       returnRn Nothing
+       rnDump rn_imp_decls rn_all_decls        `thenRn` \ dump_action ->
+       returnRn (Nothing, dump_action)
     else
 
        -- GENERATE THE VERSION/USAGE INFO
@@ -147,18 +142,17 @@ rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
     let
        has_orphans        = any isOrphanDecl rn_local_decls
        direct_import_mods = [mod | ImportDecl mod _ _ _ _ _ <- imports]
-       rn_all_decls       = rn_imp_decls ++ rn_local_decls 
        renamed_module = HsModule mod_name vers 
                                  trashed_exports trashed_imports
                                  rn_all_decls
                                  loc
     in
-    rnStats rn_imp_decls       `thenRn_`
+    rnDump rn_imp_decls        rn_all_decls            `thenRn` \ dump_action ->
     returnRn (Just (mkThisModule mod_name,
                    renamed_module, 
                    (has_orphans, my_usages, export_env),
                    name_supply,
-                   direct_import_mods))
+                   direct_import_mods), dump_action)
   where
     trashed_exports  = {-trace "rnSource:trashed_exports"-} Nothing
     trashed_imports  = {-trace "rnSource:trashed_imports"-} []
@@ -168,10 +162,13 @@ rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
 mentioned explicitly, but which might be needed by the type checker.
 
 \begin{code}
-implicitFVs mod_name
-  = implicit_main              `plusFV` 
-    mkNameSet default_tys      `plusFV`
-    mkNameSet thinAirIdNames
+implicitFVs mod_name decls
+  = mapRn lookupImplicitOccRn implicit_occs    `thenRn` \ implicit_names ->
+    returnRn (implicit_main            `plusFV` 
+             mkNameSet default_tys     `plusFV`
+             mkNameSet thinAirIdNames  `plusFV`
+             mkNameSet implicit_names)
+    
   where
        -- Add occurrences for Int, Double, and (), because they
        -- are the types to which ambigious type variables may be defaulted by
@@ -187,11 +184,30 @@ implicitFVs mod_name
     implicit_main |  mod_name == mAIN_Name
                  || mod_name == pREL_MAIN_Name = unitFV ioTyCon_NAME
                  |  otherwise                  = emptyFVs
+
+       -- Now add extra "occurrences" for things that
+       -- the deriving mechanism, or defaulting, will later need in order to
+       -- generate code
+    implicit_occs = foldr ((++) . get) [] decls
+
+    get (DefD _) = [numClass_RDR]
+    get (TyClD (TyData _ _ _ _ _ (Just deriv_classes) _ _))
+       = concat (map get_deriv deriv_classes)
+    get other = []
+
+    get_deriv cls = case lookupUFM derivingOccurrences cls of
+                       Nothing   -> []
+                       Just occs -> occs
 \end{code}
 
 \begin{code}
 isOrphanDecl (InstD (InstDecl inst_ty _ _ _ _))
-  = not (foldNameSet ((||) . isLocallyDefined) False (extractHsTyNames inst_ty))
+  = not (foldNameSet ((||) . isLocallyDefined) False (extractHsTyNames (removeContext inst_ty)))
+       -- The 'removeContext' is because of
+       --      instance Foo a => Baz T where ...
+       -- The decl is an orphan if Baz and T are both not locally defined,
+       --      even if Foo *is* locally defined
+
 isOrphanDecl (RuleD (RuleDecl _ _ _ lhs _ _))
   = check lhs
   where
@@ -215,50 +231,69 @@ slurpImpDecls source_fvs
 
        -- The current slurped-set records all local things
     getSlurped                                 `thenRn` \ source_binders ->
-    slurpSourceRefs source_binders source_fvs  `thenRn` \ (decls1, needed1, inst_gates) ->
-
-       -- Now we can get the instance decls
-    slurpInstDecls decls1 needed1 inst_gates   `thenRn` \ (decls2, needed2) ->
+    slurpSourceRefs source_binders source_fvs  `thenRn` \ (decls, needed) ->
 
        -- And finally get everything else
-    closeDecls  decls2 needed2
+    closeDecls decls needed
 
 -------------------------------------------------------
 slurpSourceRefs :: NameSet                     -- Variables defined in source
                -> FreeVars                     -- Variables referenced in source
                -> RnMG ([RenamedHsDecl],
-                        FreeVars,              -- Un-satisfied needs
-                        FreeVars)              -- "Gates"
+                        FreeVars)              -- Un-satisfied needs
 -- The declaration (and hence home module) of each gate has
 -- already been loaded
 
 slurpSourceRefs source_binders source_fvs
-  = go []                              -- Accumulating decls
-       emptyFVs                        -- Unsatisfied needs
-       source_fvs                      -- Accumulating gates
-       (nameSetToList source_fvs)      -- Gates whose defn hasn't been loaded yet
+  = go_outer []                        -- Accumulating decls
+            emptyFVs                   -- Unsatisfied needs
+            emptyFVs                   -- Accumulating gates
+            (nameSetToList source_fvs) -- Things whose defn hasn't been loaded yet
   where
-    go decls fvs gates []
+       -- The outer loop repeatedly slurps the decls for the current gates
+       -- and the instance decls 
+
+       -- The outer loop is needed because consider
+       --      instance Foo a => Baz (Maybe a) where ...
+       -- It may be that @Baz@ and @Maybe@ are used in the source module,
+       -- but not @Foo@; so we need to chase @Foo@ too.
+       --
+       -- We also need to follow superclass refs.  In particular, 'chasing @Foo@' must
+       -- include actually getting in Foo's class decl
+       --      class Wib a => Foo a where ..
+       -- so that its superclasses are discovered.  The point is that Wib is a gate too.
+       -- We do this for tycons too, so that we look through type synonyms.
+
+    go_outer decls fvs all_gates []    
+       = returnRn (decls, fvs)
+
+    go_outer decls fvs all_gates refs  -- refs are not necessarily slurped yet
+       = traceRn (text "go_outer" <+> ppr refs)                `thenRn_`
+         go_inner decls fvs emptyFVs refs                      `thenRn` \ (decls1, fvs1, gates1) ->
+         getImportedInstDecls (all_gates `plusFV` gates1)      `thenRn` \ inst_decls ->
+         rnInstDecls decls1 fvs1 gates1 inst_decls             `thenRn` \ (decls2, fvs2, gates2) ->
+         go_outer decls2 fvs2 (all_gates `plusFV` gates2)
+                              (nameSetToList (gates2 `minusNameSet` all_gates))
+               -- Knock out the all_gates because even ifwe don't slurp any new
+               -- decls we can get some apparently-new gates from wired-in names
+
+    go_inner decls fvs gates []
        = returnRn (decls, fvs, gates)
 
-    go decls fvs gates (wanted_name:refs) 
+    go_inner decls fvs gates (wanted_name:refs) 
        | isWiredInName wanted_name
        = load_home wanted_name         `thenRn_`
-         go decls fvs (gates `plusFV` getWiredInGates wanted_name) refs
+         go_inner decls fvs (gates `plusFV` getWiredInGates wanted_name) refs
 
        | otherwise
        = importDecl wanted_name                `thenRn` \ maybe_decl ->
          case maybe_decl of
-               -- No declaration... (already slurped, or local)
-           Nothing   -> go decls fvs gates refs
+           Nothing   -> go_inner decls fvs gates refs  -- No declaration... (already slurped, or local)
            Just decl -> rnIfaceDecl decl               `thenRn` \ (new_decl, fvs1) ->
-                        let
-                           new_gates = getGates source_fvs new_decl
-                        in
-                        go (new_decl : decls)
-                           (fvs1 `plusFV` fvs)
-                           (gates `plusFV` new_gates)
-                           (nameSetToList new_gates ++ refs)
+                        go_inner (new_decl : decls)
+                                 (fvs1 `plusFV` fvs)
+                                 (gates `plusFV` getGates source_fvs new_decl)
+                                 refs
 
        -- When we find a wired-in name we must load its
        -- home module so that we find any instance decls therein
@@ -275,36 +310,19 @@ slurpSourceRefs source_binders source_fvs
                                                returnRn ()
         where
          doc = ptext SLIT("need home module for wired in thing") <+> ppr name
-\end{code}
-%
-@slurpInstDecls@ imports appropriate instance decls.
-It has to incorporate a loop, because consider
-\begin{verbatim}
-       instance Foo a => Baz (Maybe a) where ...
-\end{verbatim}
-It may be that @Baz@ and @Maybe@ are used in the source module,
-but not @Foo@; so we need to chase @Foo@ too.
 
-\begin{code}
-slurpInstDecls decls needed gates
-  | isEmptyFVs gates
-  = returnRn (decls, needed)
+rnInstDecls decls fvs gates []
+  = returnRn (decls, fvs, gates)
+rnInstDecls decls fvs gates (d:ds) 
+  = rnIfaceDecl d              `thenRn` \ (new_decl, fvs1) ->
+    rnInstDecls (new_decl:decls) 
+               (fvs1 `plusFV` fvs)
+               (gates `plusFV` getInstDeclGates new_decl)
+               ds
+\end{code}
 
-  | otherwise
-  = getImportedInstDecls gates                         `thenRn` \ inst_decls ->
-    rnInstDecls decls needed emptyFVs inst_decls       `thenRn` \ (decls1, needed1, gates1) ->
-    slurpInstDecls decls1 needed1 gates1
-  where
-    rnInstDecls decls fvs gates []
-       = returnRn (decls, fvs, gates)
-    rnInstDecls decls fvs gates (d:ds) 
-       = rnIfaceDecl d         `thenRn` \ (new_decl, fvs1) ->
-         rnInstDecls (new_decl:decls) 
-                     (fvs1 `plusFV` fvs)
-                     (gates `plusFV` getInstDeclGates new_decl)
-                     ds
-    
 
+\begin{code}
 -------------------------------------------------------
 -- closeDecls keeps going until the free-var set is empty
 closeDecls decls needed
@@ -378,12 +396,12 @@ vars of the source program, and extracts from the decl the gate names.
 getGates source_fvs (SigD (IfaceSig _ ty _ _))
   = extractHsTyNames ty
 
-getGates source_fvs (TyClD (ClassDecl ctxt cls tvs sigs _ _ _ _ _ _))
+getGates source_fvs (TyClD (ClassDecl ctxt cls tvs _ sigs _ _ _ _ _ _))
   = delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) sigs)
                       (map getTyVarName tvs)
     `addOneToNameSet` cls
   where
-    get (ClassOpSig n _ ty _) 
+    get (ClassOpSig n _ _ ty _) 
        | n `elemNameSet` source_fvs = extractHsTyNames ty
        | otherwise                  = emptyFVs
 
@@ -462,10 +480,6 @@ getInstDeclGates other                                 = emptyFVs
 
 \begin{code}
 reportUnusedNames gbl_env avail_env (ExportEnv export_avails _) mentioned_names
-  | not (opt_WarnUnusedBinds || opt_WarnUnusedImports)
-  = returnRn ()
-
-  | otherwise
   = let
        used_names = mentioned_names `unionNameSets` availsToNameSet export_avails
 
@@ -476,7 +490,7 @@ reportUnusedNames gbl_env avail_env (ExportEnv export_avails _) mentioned_names
                    | sub_name <- nameSetToList used_names,
                      let avail = case lookupNameEnv avail_env sub_name of
                            Just avail -> avail
-                           Nothing -> pprTrace "r.u.n" (ppr sub_name) $
+                           Nothing -> WARN( True, text "reportUnusedName: not in avail_env" <+> ppr sub_name )
                                       Avail sub_name
                    ]
 
@@ -487,8 +501,7 @@ reportUnusedNames gbl_env avail_env (ExportEnv export_avails _) mentioned_names
        -- Filter out the ones only defined implicitly
        bad_guys = filter reportableUnusedName defined_but_not_used
     in
-    warnUnusedTopNames bad_guys        `thenRn_`
-    returnRn ()
+    warnUnusedTopNames bad_guys
 
 reportableUnusedName :: Name -> Bool
 reportableUnusedName name
@@ -500,19 +513,21 @@ reportableUnusedName name
        -- Report unused explicit imports
     explicitlyImported other                                = False
        -- Don't report others
-   
-rnStats :: [RenamedHsDecl] -> RnMG ()
-rnStats imp_decls
+
+rnDump  :: [RenamedHsDecl]     -- Renamed imported decls
+       -> [RenamedHsDecl]      -- Renamed local decls
+       -> RnMG (IO ())
+rnDump imp_decls decls
         | opt_D_dump_rn_trace || 
          opt_D_dump_rn_stats ||
          opt_D_dump_rn 
-       = getRnStats imp_decls          `thenRn` \ msg ->
-         ioToRnM (printErrs msg)       `thenRn_`
-         returnRn ()
+       = getRnStats imp_decls          `thenRn` \ stats_msg ->
 
-       | otherwise = returnRn ()
-\end{code}
+         returnRn (printErrs stats_msg >> 
+                   dumpIfSet opt_D_dump_rn "Renamer:" (vcat (map ppr decls)))
 
+       | otherwise = returnRn (return ())
+\end{code}
 
 
 %*********************************************************