Commit 39262efa authored by simonpj's avatar simonpj
Browse files

[project @ 1999-12-09 12:30:56 by simonpj]

A bunch of small changes in the way that usage information
is generated to stuff into interface files.  I'm not certain
anything was really wrong before, but it's tidier now, and
there are slightly fewer dependencies generated.  Main
differences are in RnIfaces.getImportVersions

I also made the check for orphan rules a bit cleverer
(Rename.isOrphanDecl) so that we get fewer spurious orphan modules.

Simon
parent cc471d7b
......@@ -313,7 +313,7 @@ opt_D_dump_ds = opt_D_dump_most || lookUp SLIT("-ddump-ds")
opt_D_dump_flatC = opt_D_dump_all || lookUp SLIT("-ddump-flatC")
opt_D_dump_foreign = opt_D_dump_most || lookUp SLIT("-ddump-foreign-stubs")
opt_D_dump_inlinings = opt_D_dump_all || lookUp SLIT("-ddump-inlinings")
opt_D_dump_occur_anal = opt_D_dump_most || lookUp SLIT("-ddump-occur-anal")
opt_D_dump_occur_anal = opt_D_dump_all || lookUp SLIT("-ddump-occur-anal")
opt_D_dump_parsed = opt_D_dump_most || lookUp SLIT("-ddump-parsed")
opt_D_dump_realC = opt_D_dump_all || lookUp SLIT("-ddump-realC")
opt_D_dump_rn = opt_D_dump_most || lookUp SLIT("-ddump-rn")
......
......@@ -91,7 +91,7 @@ endIface :: Maybe Handle -> IO ()
\end{code}
\begin{code}
startIface mod (has_orphans, import_usages, ExportEnv avails fixities)
startIface mod (has_orphans, import_usages, ExportEnv avails fixities _)
= case opt_ProduceHi of
Nothing -> return Nothing ; -- not producing any .hi file
......
......@@ -89,7 +89,7 @@ renameModule us this_mod@(HsModule mod_name vers exports imports local_decls loc
\begin{code}
rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
rename this_mod@(HsModule mod_name vers _ imports local_decls loc)
= -- FIND THE GLOBAL NAME ENVIRONMENT
getGlobalNames this_mod `thenRn` \ maybe_stuff ->
......@@ -130,8 +130,8 @@ rename this_mod@(HsModule mod_name vers exports imports local_decls loc)
else
-- GENERATE THE VERSION/USAGE INFO
getImportVersions mod_name exports `thenRn` \ my_usages ->
getNameSupplyRn `thenRn` \ name_supply ->
getImportVersions mod_name export_env `thenRn` \ my_usages ->
getNameSupplyRn `thenRn` \ name_supply ->
-- REPORT UNUSED NAMES
reportUnusedNames gbl_env global_avail_env
......@@ -211,9 +211,20 @@ isOrphanDecl (InstD (InstDecl inst_ty _ _ _ _))
isOrphanDecl (RuleD (RuleDecl _ _ _ lhs _ _))
= check lhs
where
check (HsVar v) = not (isLocallyDefined v)
check (HsApp f a) = check f && check a
check other = True
-- At the moment we just check for common LHS forms
-- Expand as necessary. Getting it wrong just means
-- more orphans than necessary
check (HsVar v) = not (isLocallyDefined v)
check (HsApp f a) = check f && check a
check (HsLit _) = False
check (OpApp l o _ r) = check l && check o && check r
check (NegApp e _) = check e
check (HsPar e) = check e
check (SectionL e o) = check e && check o
check (SectionR o e) = check e && check o
check other = True -- Safe fall through
isOrphanDecl other = False
\end{code}
......@@ -479,7 +490,7 @@ getInstDeclGates other = emptyFVs
%*********************************************************
\begin{code}
reportUnusedNames gbl_env avail_env (ExportEnv export_avails _) mentioned_names
reportUnusedNames gbl_env avail_env (ExportEnv export_avails _ _) mentioned_names
= let
used_names = mentioned_names `unionNameSets` availsToNameSet export_avails
......
......@@ -40,7 +40,7 @@ import RnMonad
import RnHsSyn ( RenamedHsDecl )
import ParseIface ( parseIface, IfaceStuff(..) )
import FiniteMap ( FiniteMap, sizeFM, emptyFM, delFromFM,
import FiniteMap ( FiniteMap, sizeFM, emptyFM, delFromFM, listToFM,
lookupFM, addToFM, addToFM_C, addListToFM,
fmToList, elemFM, foldFM
)
......@@ -630,13 +630,13 @@ lookupFixity name
%* *
%*********************************************************
getImportVersions figures out
what the ``usage information'' for this moudule is;
that is, what it must record in its interface file as the things it uses.
It records:
getImportVersions figures out what the ``usage information'' for this
moudule is; that is, what it must record in its interface file as the
things it uses. It records:
\begin{itemize}
\item anything reachable from its body code
\item any module exported with a @module Foo@.
\item anything reachable from its body code
\item any module exported with a @module Foo@.
\end{itemize}
%
Why the latter? Because if @Foo@ changes then this module's export list
......@@ -650,92 +650,121 @@ What about this?
import B( f ) | f = h 3
g = ... | h = ...
\end{verbatim}
Should we record @B.f@ in @A@'s usages? In fact we don't. Certainly, if
anything about @B.f@ changes than anyone who imports @A@ should be recompiled;
they'll get an early exit if they don't use @B.f@. However, even if @B.f@
doesn't change at all, @B.h@ may do so, and this change may not be reflected
in @f@'s version number. So there are two things going on when compiling module @A@:
Should we record @B.f@ in @A@'s usages? In fact we don't. Certainly,
if anything about @B.f@ changes than anyone who imports @A@ should be
recompiled; they'll get an early exit if they don't use @B.f@.
However, even if @B.f@ doesn't change at all, @B.h@ may do so, and
this change may not be reflected in @f@'s version number. So there
are two things going on when compiling module @A@:
\begin{enumerate}
\item Are @A.o@ and @A.hi@ correct? Then we can bale out early.
\item Should modules that import @A@ be recompiled?
\item Are @A.o@ and @A.hi@ correct? Then we can bale out early.
\item Should modules that import @A@ be recompiled?
\end{enumerate}
For (1) it is slightly harmful to record @B.f@ in @A@'s usages,
because a change in @B.f@'s version will provoke full recompilation of @A@,
producing an identical @A.o@,
and @A.hi@ differing only in its usage-version of @B.f@
(and this usage-version info isn't used by any importer).
For (2), because of the tricky @B.h@ question above,
we ensure that @A.hi@ is touched
(even if identical to its previous version)
if A's recompilation was triggered by an imported @.hi@ file date change.
because a change in @B.f@'s version will provoke full recompilation of
@A@, producing an identical @A.o@, and @A.hi@ differing only in its
usage-version of @B.f@ (and this usage-version info isn't used by any
importer).
For (2), because of the tricky @B.h@ question above, we ensure that
@A.hi@ is touched (even if identical to its previous version) if A's
recompilation was triggered by an imported @.hi@ file date change.
Given that, there's no need to record @B.f@ in @A@'s usages.
On the other hand, if @A@ exports @module B@,
then we {\em do} count @module B@ among @A@'s usages,
because we must recompile @A@ to ensure that @A.hi@ changes appropriately.
On the other hand, if @A@ exports @module B@, then we {\em do} count
@module B@ among @A@'s usages, because we must recompile @A@ to ensure
that @A.hi@ changes appropriately.
HOWEVER, we *do* record the usage
import B <n> :: ;
in A.hi, to record the fact that A does import B. This is used to decide
to look to look for B.hi rather than B.hi-boot when compiling a module that
imports A. This line says that A imports B, but uses nothing in it.
So we'll get an early bale-out when compiling A if B's version changes.
\begin{code}
getImportVersions :: ModuleName -- Name of this module
-> Maybe [IE any] -- Export list for this module
-> ExportEnv -- Info about exports
-> RnMG (VersionInfo Name) -- Version info for these names
getImportVersions this_mod exports
getImportVersions this_mod (ExportEnv export_avails _ export_all_mods)
= getIfacesRn `thenRn` \ ifaces ->
let
mod_map = iImpModInfo ifaces
imp_names = iVSlurp ifaces
export_mods :: FiniteMap ModuleName () -- Set of home modules for
-- things in the export list
export_mods = listToFM [(moduleName (nameModule (availName a)), ()) | a <- export_avails]
-- mv_map groups together all the things imported from a particular module.
mv_map1, mv_map2 :: FiniteMap ModuleName (WhatsImported Name)
-- mv_map1 records all the modules that have a "module M"
-- in this module's export list with an "Everything"
mv_map1 = foldr add_mod emptyFM export_mods
-- mv_map2 adds the version numbers of things exported individually
mv_map2 = foldr add_mv mv_map1 imp_names
mv_map :: FiniteMap ModuleName [(Name,Version)]
mv_map = foldr add_mv emptyFM imp_names
-- Build the result list by adding info for each module.
-- For (a) library modules
-- (b) source-imported modules
-- we do something special. We don't want to record detailed usage information.
-- Indeed we don't want to record them at all unless they contain orphans,
-- which we must never lose track of.
mk_version_info mod_name (version, has_orphans, cts) so_far
| lib_or_source_imported && not has_orphans
= so_far -- Don't record any usage info for this module
-- For (a) a library module, we don't record it at all unless it contains orphans
-- (We must never lose track of orphans.)
--
-- (b) a source-imported module, don't record the dependency at all
--
-- (b) may seem a bit strange. The idea is that the usages in a .hi file records
-- *all* the module's dependencies other than the loop-breakers. We use
-- this info in findAndReadInterface to decide whether to look for a .hi file or
-- a .hi-boot file.
--
-- This means we won't track version changes, or orphans, from .hi-boot files.
-- The former is potentially rather bad news. It could be fixed by recording
-- whether something is a boot file along with the usage info for it, but
-- I can't be bothered just now.
mk_version_info mod_name (version, has_orphans, Nothing) so_far
= ASSERT( not has_orphans ) -- If has_orphans is true we will have opened it
so_far -- We didn't even read this module's interface
-- so don't record dependency on it.
mk_version_info mod_name (version, has_orphans, Just (mod, boot_import, _)) so_far
| boot_import -- Don't record any usage info for this module
|| (is_lib_module && not has_orphans)
= so_far
| lib_or_source_imported -- Has orphans; record the module but not
-- detailed version information for the imports
= (mod_name, version, has_orphans, Specifically []) : so_far
| otherwise
= (mod_name, version, has_orphans, whats_imported) : so_far
| is_lib_module -- Record the module but not
|| mod_name `elem` export_all_mods -- detailed version information for the imports
= go_for_it Everything
| otherwise
= case lookupFM mv_map mod_name of
Just whats_imported
-> go_for_it (Specifically whats_imported)
Nothing -- This happens if you have
-- import Foo
-- but don't actually *use* anything from Foo
| has_orphans -- Check for (a) orphans (we must never forget them)
|| mod_name `elemFM` export_mods -- or (b) something from the module is exported
-> -- ...in which case record an empty dependency list
go_for_it (Specifically [])
| otherwise -> so_far -- No point in recording any dependency
where
whats_imported = case lookupFM mv_map2 mod_name of
Just wi -> wi
Nothing -> Specifically []
is_lib_module = isLibModule mod
go_for_it exports = (mod_name, version, has_orphans, exports) : so_far
lib_or_source_imported = case cts of
Just (mod, boot_import, _) -> isLibModule mod || boot_import
Nothing -> False
in
-- A module shouldn't load its own interface
-- This seems like a convenient place to check
WARN( maybeToBool (lookupFM mod_map this_mod),
ptext SLIT("Wierd:") <+> ppr this_mod <+> ptext SLIT("loads its own interface") )
returnRn (foldFM mk_version_info [] mod_map)
where
export_mods = case exports of
Nothing -> []
Just es -> [mod | IEModuleContents mod <- es, mod /= this_mod]
add_mv v@(name, version) mv_map
= addToFM_C add_item mv_map mod (Specifically [v])
where
= addToFM_C add_item mv_map mod [v]
where
mod = moduleName (nameModule name)
add_item Everything _ = Everything
add_item (Specifically xs) _ = Specifically (v:xs)
add_mod mod mv_map = addToFM mv_map mod Everything
add_item vs _ = (v:vs)
\end{code}
\begin{code}
......
......@@ -218,7 +218,10 @@ type RnNameSupply
--------------------------------
data ExportEnv = ExportEnv Avails Fixities
data ExportEnv = ExportEnv Avails Fixities [ModuleName]
-- The list of modules is the modules exported
-- with 'module M' in the export list
type Avails = [AvailInfo]
type Fixities = [(Name, Fixity)]
......@@ -287,7 +290,7 @@ type InterfaceDetails = (WhetherHasOrphans,
-- needed by Main to fish out the fixities assoc list.
getIfaceFixities :: InterfaceDetails -> Fixities
getIfaceFixities (_, _, ExportEnv _ fs) = fs
getIfaceFixities (_, _, ExportEnv _ fs _) = fs
type RdrNamePragma = () -- Fudge for now
......@@ -453,7 +456,9 @@ renameSourceCode mod_name name_supply m
let
rn_down = RnDown { rn_loc = mkGeneratedSrcLoc, rn_ns = names_var,
rn_errs = errs_var, rn_hi_maps = himaps,
rn_mod = mod_name }
rn_mod = mod_name,
rn_ifaces = panic "rnameSourceCode: rn_ifaces" -- Not required
}
s_down = SDown { rn_mode = InterfaceMode,
-- So that we can refer to PrelBase.True etc
rn_genv = emptyRdrEnv, rn_lenv = emptyRdrEnv,
......
......@@ -142,8 +142,7 @@ getGlobalNames (HsModule this_mod _ exports imports decls mod_loc)
isQual rdr_name]) `thenRn_`
-- PROCESS EXPORT LISTS
exportsFromAvail this_mod exports all_avails gbl_env
`thenRn` \ exported_avails ->
exportsFromAvail this_mod exports all_avails gbl_env `thenRn` \ exported_avails ->
-- DONE
returnRn (gbl_env, exported_avails, Just all_avails)
......@@ -164,14 +163,17 @@ getGlobalNames (HsModule this_mod _ exports imports decls mod_loc)
| FixitySig name fixity _ <- nameEnvElts local_fixity_env,
isLocallyDefined name
]
in
traceRn (text "fixity env" <+> vcat (map ppr (nameEnvElts local_fixity_env))) `thenRn_`
--- TIDY UP
let
export_env = ExportEnv exported_avails exported_fixities
-- CONSTRUCT RESULTS
export_mods = case exports of
Nothing -> []
Just es -> [mod | IEModuleContents mod <- es, mod /= this_mod]
export_env = ExportEnv exported_avails exported_fixities export_mods
(_, global_avail_env) = all_avails
in
traceRn (text "fixity env" <+> vcat (map ppr (nameEnvElts local_fixity_env))) `thenRn_`
returnRn (Just (export_env, gbl_env, local_fixity_env, global_avail_env))
}
where
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment