[project @ 1999-12-06 11:54:56 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / Rename.lhs
index ca22b19..730f02d 100644 (file)
@@ -44,9 +44,7 @@ import PrelMods               ( mAIN_Name, pREL_MAIN_Name )
 import TysWiredIn      ( unitTyCon, intTyCon, doubleTyCon, boolTyCon )
 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 )
@@ -74,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}
 
 
@@ -107,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
@@ -128,13 +117,16 @@ rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
                -- 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
@@ -150,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"-} []
@@ -240,47 +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) ->
-                        go (new_decl : decls)
-                           (fvs1 `plusFV` fvs)
-                           (gates `plusFV` getGates source_fvs new_decl)
-                           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
@@ -297,39 +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
-  = go decls needed gates gates
-  where
-    go decls needed all_gates new_gates
-       | isEmptyFVs new_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 all_gates                `thenRn` \ inst_decls ->
-         rnInstDecls decls needed emptyFVs inst_decls  `thenRn` \ (decls1, needed1, new_gates) ->
-         go decls1 needed1 (all_gates `plusFV` new_gates) new_gates
-
-    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
@@ -403,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
 
@@ -521,18 +514,20 @@ reportableUnusedName name
     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}
 
 
 %*********************************************************