Convert more UniqFM's back to LazyUniqFM's
[ghc-hetmet.git] / compiler / iface / MkIface.lhs
index 0fc3972..124e7aa 100644 (file)
@@ -4,12 +4,21 @@
 %
 
 \begin{code}
-module MkIface ( 
-       mkUsageInfo,    -- Construct the usage info for a module
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
 
+module MkIface ( 
+        mkUsedNames,
+        mkDependencies,
        mkIface,        -- Build a ModIface from a ModGuts, 
                        -- including computing version information
 
+        mkIfaceTc,
+
        writeIfaceFile, -- Write the interface file
 
        checkOldIface,  -- See if recompilation is required, by
@@ -122,7 +131,7 @@ We produce a line for every module B below the module, A, currently being
 compiled:
        import B <n> ;
 to record the fact that A does import B indirectly.  This is used to decide
-to look to look for B.hi rather than B.hi-boot when compiling a module that
+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.
 
@@ -172,6 +181,10 @@ code of A, and thereby haul in all the stuff reachable from it.
 haul in all the unfoldings for B, in case the module that imports A *is*
 compiled with -O.  I think this is the case.]
 
+SimonM [30/11/2007]: I believe the above is all out of date; the
+current implementation doesn't do it this way.  Instead, when any of
+the dependencies of a declaration changes, the version of the
+declaration itself changes.
 
 \begin{code}
 #include "HsVersions.h"
@@ -183,6 +196,7 @@ import Id
 import IdInfo
 import NewDemand
 import CoreSyn
+import CoreFVs
 import Class
 import TyCon
 import DataCon
@@ -192,8 +206,10 @@ import InstEnv
 import FamInstEnv
 import TcRnMonad
 import HscTypes
-
+import Finder
 import DynFlags
+import VarEnv
+import Var
 import Name
 import NameEnv
 import NameSet
@@ -207,14 +223,17 @@ import SrcLoc
 import PackageConfig    hiding ( Version )
 import Outputable
 import BasicTypes       hiding ( SuccessFlag(..) )
-import UniqFM
+import LazyUniqFM
 import Util             hiding ( eqListBy )
 import FiniteMap
 import FastString
 import Maybes
+import ListSetOps
 
 import Control.Monad
 import Data.List
+import Data.IORef
+import System.FilePath
 \end{code}
 
 
@@ -228,46 +247,137 @@ import Data.List
 \begin{code}
 mkIface :: HscEnv
        -> Maybe ModIface       -- The old interface, if we have it
-       -> ModGuts              -- Usages, deprecations, etc
        -> ModDetails           -- The trimmed, tidied interface
+       -> ModGuts              -- Usages, deprecations, etc
        -> IO (ModIface,        -- The new one, complete with decls and versions
               Bool)            -- True <=> there was an old Iface, and the new one
                                --          is identical, so no need to write it
 
-mkIface hsc_env maybe_old_iface 
-       (ModGuts{     mg_module    = this_mod,
+mkIface hsc_env maybe_old_iface mod_details
+        ModGuts{     mg_module    = this_mod,
                      mg_boot      = is_boot,
-                     mg_usages    = usages,
+                     mg_used_names = used_names,
                      mg_deps      = deps,
+                      mg_dir_imps  = dir_imp_mods,
                      mg_rdr_env   = rdr_env,
                      mg_fix_env   = fix_env,
-                     mg_deprecs   = src_deprecs })
-       (ModDetails{  md_insts     = insts, 
+                     mg_deprecs   = deprecs,
+                     mg_hpc_info  = hpc_info }
+        = mkIface_ hsc_env maybe_old_iface
+                   this_mod is_boot used_names deps rdr_env 
+                   fix_env deprecs hpc_info dir_imp_mods mod_details
+       
+-- | make an interface from the results of typechecking only.  Useful
+-- for non-optimising compilation, or where we aren't generating any
+-- object code at all ('HscNothing').
+mkIfaceTc :: HscEnv
+          -> Maybe ModIface    -- The old interface, if we have it
+          -> ModDetails                -- gotten from mkBootModDetails, probably
+          -> TcGblEnv          -- Usages, deprecations, etc
+         -> IO (ModIface,
+                Bool)
+mkIfaceTc hsc_env maybe_old_iface mod_details
+  tc_result@TcGblEnv{ tcg_mod = this_mod,
+                      tcg_src = hsc_src,
+                      tcg_imports = imports,
+                      tcg_rdr_env = rdr_env,
+                      tcg_fix_env = fix_env,
+                      tcg_deprecs = deprecs,
+                      tcg_hpc = other_hpc_info
+                    }
+  = do
+          used_names <- mkUsedNames tc_result
+          deps <- mkDependencies tc_result
+          let hpc_info = emptyHpcInfo other_hpc_info
+          mkIface_ hsc_env maybe_old_iface
+                   this_mod (isHsBoot hsc_src) used_names deps rdr_env 
+                   fix_env deprecs hpc_info (imp_mods imports) mod_details
+        
+
+mkUsedNames :: TcGblEnv -> IO NameSet
+mkUsedNames 
+          TcGblEnv{ tcg_inst_uses = dfun_uses_var,
+                    tcg_dus = dus
+                  }
+ = do
+        dfun_uses <- readIORef dfun_uses_var           -- What dfuns are used
+        return (allUses dus `unionNameSets` dfun_uses)
+        
+mkDependencies :: TcGblEnv -> IO Dependencies
+mkDependencies
+          TcGblEnv{ tcg_mod = mod,
+                    tcg_imports = imports,
+                    tcg_th_used = th_var
+                  }
+ = do 
+      th_used   <- readIORef th_var                        -- Whether TH is used
+      let
+        dep_mods = eltsUFM (delFromUFM (imp_dep_mods imports) (moduleName mod))
+                -- M.hi-boot can be in the imp_dep_mods, but we must remove
+                -- it before recording the modules on which this one depends!
+                -- (We want to retain M.hi-boot in imp_dep_mods so that 
+                --  loadHiBootInterface can see if M's direct imports depend 
+                --  on M.hi-boot, and hence that we should do the hi-boot consistency 
+                --  check.)
+
+        dir_imp_mods = imp_mods imports
+
+                -- Modules don't compare lexicographically usually, 
+                -- but we want them to do so here.
+        le_mod :: Module -> Module -> Bool         
+        le_mod m1 m2 = moduleNameFS (moduleName m1) 
+                           <= moduleNameFS (moduleName m2)
+
+        le_dep_mod :: (ModuleName, IsBootInterface)
+                    -> (ModuleName, IsBootInterface) -> Bool         
+        le_dep_mod (m1,_) (m2,_) = moduleNameFS m1 <= moduleNameFS m2
+
+        
+        pkgs | th_used   = insertList thPackageId (imp_dep_pkgs imports)
+             | otherwise = imp_dep_pkgs imports
+
+      return Deps { dep_mods   = sortLe le_dep_mod dep_mods,
+                    dep_pkgs   = sortLe (<=)   pkgs,        
+                    dep_orphs  = sortLe le_mod (imp_orphs  imports),
+                    dep_finsts = sortLe le_mod (imp_finsts imports) }
+                -- sort to get into canonical order
+
+
+mkIface_ hsc_env maybe_old_iface 
+         this_mod is_boot used_names deps rdr_env fix_env src_deprecs hpc_info
+         dir_imp_mods
+        ModDetails{  md_insts     = insts, 
                      md_fam_insts = fam_insts,
                      md_rules     = rules,
+                      md_vect_info = vect_info,
                      md_types     = type_env,
-                     md_exports   = exports })
-       
+                     md_exports   = exports }
 -- NB: notice that mkIface does not look at the bindings
 --     only at the TypeEnv.  The previous Tidy phase has
 --     put exactly the info into the TypeEnv that we want
 --     to expose in the interface
 
-  = do { eps <- hscEPS hsc_env
+  = do {eps <- hscEPS hsc_env
+
+       ; usages <- mkUsageInfo hsc_env dir_imp_mods (dep_mods deps) used_names
+
        ; let   { entities = typeEnvElts type_env ;
                   decls  = [ tyThingToIfaceDecl entity
                           | entity <- entities,
-                             not (isImplicitTyThing entity
-                                  || isWiredInName (getName entity)) ]
-                        -- Don't put implicit Ids and class tycons in
-                        -- the interface file, Nor wired-in things; the
-                        -- compiler knows about them anyhow
-
-               ; fixities    = [(occ,fix) | FixItem occ fix _ <- nameEnvElts fix_env]
-               ; deprecs     = mkIfaceDeprec src_deprecs
-               ; iface_rules = map coreRuleToIfaceRule rules
+                            let name = getName entity,
+                             not (isImplicitTyThing entity),
+                               -- No implicit Ids and class tycons in the interface file
+                            not (isWiredInName name),
+                               -- Nor wired-in things; the compiler knows about them anyhow
+                            nameIsLocalOrFrom this_mod name  ]
+                               -- Sigh: see Note [Root-main Id] in TcRnDriver
+
+               ; fixities    = [(occ,fix) | FixItem occ fix <- nameEnvElts fix_env]
+               ; deprecs     = src_deprecs
+               ; iface_rules = map (coreRuleToIfaceRule this_mod) rules
                ; iface_insts = map instanceToIfaceInst insts
                ; iface_fam_insts = map famInstToIfaceFamInst fam_insts
+                ; iface_vect_info = flattenVectInfo vect_info
 
                ; intermediate_iface = ModIface { 
                        mi_module   = this_mod,
@@ -282,6 +392,8 @@ mkIface hsc_env maybe_old_iface
                        mi_fam_insts= sortLe le_fam_inst iface_fam_insts,
                        mi_rules    = sortLe le_rule iface_rules,
 
+                        mi_vect_info = iface_vect_info,
+
                        mi_fixities = fixities,
                        mi_deprecs  = deprecs,
                        mi_globals  = Just rdr_env,
@@ -295,6 +407,7 @@ mkIface hsc_env maybe_old_iface
                         mi_finsts    = False,   -- Ditto
                        mi_decls     = deliberatelyOmitted "decls",
                        mi_ver_fn    = deliberatelyOmitted "ver_fn",
+                       mi_hpc       = isHpcUsed hpc_info,
 
                        -- And build the cached values
                        mi_dep_fn = mkIfaceDepCache deprecs,
@@ -303,7 +416,7 @@ mkIface hsc_env maybe_old_iface
                -- Add version information
                 ; ext_ver_fn = mkParentVerFun hsc_env eps
                ; (new_iface, no_change_at_all, pp_diffs, pp_orphs) 
-                       = _scc_ "versioninfo" 
+                       = {-# SCC "versioninfo" #-}
                         addVersionInfo ext_ver_fn maybe_old_iface
                                          intermediate_iface decls
                }
@@ -315,7 +428,13 @@ mkIface hsc_env maybe_old_iface
        ; dumpIfSet_dyn dflags Opt_D_dump_hi "FINAL INTERFACE" 
                        (pprModIface new_iface)
 
-       ; return (new_iface, no_change_at_all) }
+                -- bug #1617: on reload we weren't updating the PrintUnqualified
+                -- correctly.  This stems from the fact that the interface had
+                -- not changed, so addVersionInfo returns the old ModIface
+                -- with the old GlobalRdrEnv (mi_globals).
+        ; let final_iface = new_iface{ mi_globals = Just rdr_env }
+
+       ; return (final_iface, no_change_at_all) }
   where
      r1 `le_rule`     r2 = ifRuleName      r1    <=    ifRuleName      r2
      i1 `le_inst`     i2 = ifDFun          i1 `le_occ` ifDFun          i2  
@@ -330,11 +449,24 @@ mkIface hsc_env maybe_old_iface
      deliberatelyOmitted x = panic ("Deliberately omitted: " ++ x)
      ifFamInstTcName = ifaceTyConName . ifFamInstTyCon
 
-                                             
+     flattenVectInfo (VectInfo { vectInfoVar   = vVar
+                               , vectInfoTyCon = vTyCon
+                               }) = 
+       IfaceVectInfo { 
+         ifaceVectInfoVar        = [ Var.varName v 
+                                   | (v, _) <- varEnvElts vVar],
+         ifaceVectInfoTyCon      = [ tyConName t 
+                                   | (t, t_v) <- nameEnvElts vTyCon
+                                   , t /= t_v],
+         ifaceVectInfoTyConReuse = [ tyConName t
+                                   | (t, t_v) <- nameEnvElts vTyCon
+                                   , t == t_v]
+       } 
+
 -----------------------------
 writeIfaceFile :: DynFlags -> ModLocation -> ModIface -> IO ()
 writeIfaceFile dflags location new_iface
-    = do createDirectoryHierarchy (directoryOf hi_file_path)
+    = do createDirectoryHierarchy (takeDirectory hi_file_path)
          writeBinIface dflags hi_file_path new_iface
     where hi_file_path = ml_hi_file location
 
@@ -379,8 +511,7 @@ addVersionInfo
 
 addVersionInfo ver_fn Nothing new_iface new_decls
 -- No old interface, so definitely write a new one!
-  = (new_iface { mi_orphan = anyNothing ifInstOrph (mi_insts new_iface)
-                                || anyNothing ifRuleOrph (mi_rules new_iface)
+  = (new_iface { mi_orphan = not (null orph_insts && null orph_rules)
                , mi_finsts = not . null $ mi_fam_insts new_iface
                , mi_decls  = [(initialVersion, decl) | decl <- new_decls]
                , mi_ver_fn = mkIfaceVerCache (zip (repeat initialVersion) 
@@ -451,7 +582,8 @@ addVersionInfo ver_fn (Just old_iface@(ModIface {
 
        -- If the usages havn't changed either, we don't need to write the interface file
     no_other_changes = mi_usages new_iface == mi_usages old_iface && 
-                      mi_deps new_iface == mi_deps old_iface
+                      mi_deps new_iface == mi_deps old_iface &&
+                      mi_hpc new_iface == mi_hpc old_iface
     no_change_at_all = no_output_change && no_other_changes
  
     pp_diffs = vcat [pp_change no_export_change "Export list" 
@@ -537,7 +669,7 @@ addVersionInfo ver_fn (Just old_iface@(ModIface {
        where
          occ = ifName new_decl
          why = case lookupOccEnv eq_env occ of
-                   Just (EqBut names) -> sep [ppr occ <> colon, ptext SLIT("Free vars (only) changed:"),
+                   Just (EqBut names) -> sep [ppr occ <> colon, ptext SLIT("Free vars (only) changed:") <> ppr names,
                                              nest 2 (braces (fsep (map ppr (occSetElts 
                                                (occs `intersectOccSet` changed_occs)))))]
                            where occs = mkOccSet (map nameOccName (nameSetToList names))
@@ -577,20 +709,28 @@ computeChangedOccs ver_fn this_module old_usages eq_info
     -- return True if an external name has changed
     name_changed :: Name -> Bool
     name_changed nm
-        | Just ents <- lookupUFM usg_modmap (moduleName mod) 
-        = case lookupUFM ents parent_occ of
-                Nothing -> pprPanic "computeChangedOccs" (ppr nm)
-                Just v  -> v < new_version
+       | isWiredInName nm      -- Wired-in things don't get into interface
+       = False                 -- files and hence don't get into the ver_fn
+        | Just ents <- lookupUFM usg_modmap (moduleName mod),
+          Just v    <- lookupUFM ents parent_occ
+        = v < new_version
+        | modulePackageId mod == this_pkg
+        = WARN(True, ptext SLIT("computeChangedOccs") <+> ppr nm) True
+        -- should really be a panic, see #1959.  The problem is that the usages doesn't
+        -- contain all the names that might be referred to by unfoldings.  So as a
+        -- conservative workaround we just assume these names have changed.
         | otherwise = False -- must be in another package
       where
          mod = nameModule nm
          (parent_occ, new_version) = ver_fn nm
 
+    this_pkg = modulePackageId this_module
+
     -- Turn the usages from the old ModIface into a mapping
-    usg_modmap = listToUFM [ (usg_mod usg, listToUFM (usg_entities usg))
+    usg_modmap = listToUFM [ (usg_name usg, listToUFM (usg_entities usg))
                            | usg <- old_usages ]
 
-    get_local_eq_info :: GenIfaceEq NameSet -> GenIfaceEq OccSet
+    get_local_eq_info :: GenIfaceEq Name -> GenIfaceEq OccName
     get_local_eq_info Equal = Equal
     get_local_eq_info NotEqual = NotEqual
     get_local_eq_info (EqBut ns) = foldNameSet f Equal ns
@@ -620,7 +760,7 @@ computeChangedOccs ver_fn this_module old_usages eq_info
         where (occs, iface_eqs) = unzip pairs
     add_changes so_far other = so_far
 
-type OccIfaceEq = GenIfaceEq OccSet
+type OccIfaceEq = GenIfaceEq OccName
 
 changedWrt :: OccSet -> OccIfaceEq -> Bool
 changedWrt so_far Equal        = False
@@ -659,16 +799,6 @@ mkOrphMap get_key decls
        = (extendOccEnv_C (\ ds _ -> d:ds) non_orphs occ [d], orphs)
        | otherwise = (non_orphs, d:orphs)
 
-anyNothing :: (a -> Maybe b) -> [a] -> Bool
-anyNothing p []     = False
-anyNothing p (x:xs) = isNothing (p x) || anyNothing p xs
-
-----------------------
-mkIfaceDeprec :: Deprecations -> IfaceDeprecs
-mkIfaceDeprec NoDeprecs        = NoDeprecs
-mkIfaceDeprec (DeprecAll t)    = DeprecAll t
-mkIfaceDeprec (DeprecSome env) = DeprecSome (sortLe (<=) (nameEnvElts env))
-
 ----------------------
 bump_unless :: Bool -> Version -> Version
 bump_unless True  v = v        -- True <=> no change
@@ -685,7 +815,7 @@ bump_unless False v = bumpVersion v
 
 \begin{code}
 mkUsageInfo :: HscEnv 
-           -> ModuleEnv (Module, Bool, SrcSpan)
+           -> ModuleEnv (Module, [(ModuleName, Bool, SrcSpan)])
            -> [(ModuleName, IsBootInterface)]
            -> NameSet -> IO [Usage]
 mkUsageInfo hsc_env dir_imp_mods dep_mods used_names
@@ -697,6 +827,12 @@ mkUsageInfo hsc_env dir_imp_mods dep_mods used_names
         -- don't get evaluated for a while and we can end up hanging on to
         -- the entire collection of Ifaces.
 
+mk_usage_info :: PackageIfaceTable
+              -> HscEnv
+              -> ModuleEnv (Module, [(ModuleName, Bool, SrcSpan)])
+              -> [(ModuleName, IsBootInterface)]
+              -> NameSet
+              -> [Usage]
 mk_usage_info pit hsc_env dir_imp_mods dep_mods used_names
   = mapCatMaybes mkUsage dep_mods
        -- ToDo: do we need to sort into canonical order?
@@ -719,8 +855,8 @@ mk_usage_info pit hsc_env dir_imp_mods dep_mods used_names
                     add_item occs _ = occ:occs
     
     depend_on_exports mod = case lookupModuleEnv dir_imp_mods mod of
-                               Just (_,no_imp,_) -> not no_imp
-                               Nothing           -> True
+                               Just (_, xs) -> any (\(_, no_imp, _) -> not no_imp) xs
+                               Nothing          -> True
     
     -- We want to create a Usage for a home module if 
     -- a) we used something from; has something in used_names
@@ -786,23 +922,55 @@ mkIfaceExports exports
     | (mod, avails) <- fmToList groupFM
     ]
   where
+       -- Group by the module where the exported entities are defined
+       -- (which may not be the same for all Names in an Avail)
        -- Deliberately use FiniteMap rather than UniqFM so we
        -- get a canonical ordering
     groupFM :: ModuleEnv (FiniteMap FastString (GenAvailInfo OccName))
     groupFM = foldl add emptyModuleEnv exports
 
-    add env avail
-      = extendModuleEnv_C add_avail env mod (unitFM avail_fs avail_occ)
+    add_one :: ModuleEnv (FiniteMap FastString (GenAvailInfo OccName))
+           -> Module -> GenAvailInfo OccName
+           -> ModuleEnv (FiniteMap FastString (GenAvailInfo OccName))
+    add_one env mod avail 
+      =  extendModuleEnv_C plusFM env mod 
+               (unitFM (occNameFS (availName avail)) avail)
+
+       -- NB: we should not get T(X) and T(Y) in the export list
+       --     else the plusFM will simply discard one!  They
+       --     should have been combined by now.
+    add env (Avail n)
+      = add_one env (nameModule n) (Avail (nameOccName n))
+
+    add env (AvailTC tc ns)
+      = foldl add_for_mod env mods
       where
-       avail_occ = availToOccs avail
-       mod  = nameModule (availName avail)
-       avail_fs = occNameFS (availName avail_occ)
-       add_avail avail_fm _ = addToFM avail_fm avail_fs avail_occ
-
-    availToOccs (Avail n) = Avail (nameOccName n)
-    availToOccs (AvailTC tc ns) = AvailTC (nameOccName tc) (map nameOccName ns)
+       tc_occ = nameOccName tc
+       mods   = nub (map nameModule ns)
+               -- Usually just one, but see Note [Original module]
+
+       add_for_mod env mod
+           = add_one env mod (AvailTC tc_occ (sort names_from_mod))
+              -- NB. sort the children, we need a canonical order
+           where
+             names_from_mod = [nameOccName n | n <- ns, nameModule n == mod]
 \end{code}
 
+Note [Orignal module]
+~~~~~~~~~~~~~~~~~~~~~
+Consider this:
+       module X where { data family T }
+       module Y( T(..) ) where { import X; data instance T Int = MkT Int }
+The exported Avail from Y will look like
+       X.T{X.T, Y.MkT}
+That is, in Y, 
+  - only MkT is brought into scope by the data instance;
+  - but the parent (used for grouping and naming in T(..) exports) is X.T
+  - and in this case we export X.T too
+
+In the result of MkIfaceExports, the names are grouped by defining module,
+so we may need to split up a single Avail into multiple ones.
+
 
 %************************************************************************
 %*                                                                     *
@@ -830,20 +998,19 @@ checkOldIface hsc_env mod_summary source_unchanged maybe_iface
 
 check_old_iface hsc_env mod_summary source_unchanged maybe_iface
  =  do         -- CHECK WHETHER THE SOURCE HAS CHANGED
-    { ifM (not source_unchanged)
+    { when (not source_unchanged)
           (traceHiDiffs (nest 4 (text "Source file changed or recompilation check turned off")))
 
      -- If the source has changed and we're in interactive mode, avoid reading
      -- an interface; just return the one we might have been supplied with.
-    ; ghc_mode <- getGhcMode
-    ; if (ghc_mode == Interactive || ghc_mode == JustTypecheck) 
-        && not source_unchanged then
+    ; let dflags = hsc_dflags hsc_env
+    ; if not (isObjectTarget (hscTarget dflags)) && not source_unchanged then
          return (outOfDate, maybe_iface)
       else
       case maybe_iface of {
         Just old_iface -> do -- Use the one we already have
          { traceIf (text "We already have the old interface for" <+> ppr (ms_mod mod_summary))
-         ; recomp <- checkVersions hsc_env source_unchanged old_iface
+         ; recomp <- checkVersions hsc_env source_unchanged mod_summary old_iface
          ; return (recomp, Just old_iface) }
 
       ; Nothing -> do
@@ -862,9 +1029,10 @@ check_old_iface hsc_env mod_summary source_unchanged maybe_iface
 
        -- We have got the old iface; check its versions
     { traceIf (text "Read the interface file" <+> text iface_path)
-    ; recomp <- checkVersions hsc_env source_unchanged iface
-    ; returnM (recomp, Just iface)
+    ; recomp <- checkVersions hsc_env source_unchanged mod_summary iface
+    ; return (recomp, Just iface)
     }}}}}
+
 \end{code}
 
 @recompileRequired@ is called from the HscMain.   It checks whether
@@ -879,15 +1047,19 @@ outOfDate = True -- Recompile required
 
 checkVersions :: HscEnv
              -> Bool           -- True <=> source unchanged
+              -> ModSummary
              -> ModIface       -- Old interface
              -> IfG RecompileRequired
-checkVersions hsc_env source_unchanged iface
+checkVersions hsc_env source_unchanged mod_summary iface
   | not source_unchanged
-  = returnM outOfDate
+  = return outOfDate
   | otherwise
   = do { traceHiDiffs (text "Considering whether compilation is required for" <+> 
                        ppr (mi_module iface) <> colon)
 
+        ; recomp <- checkDependencies hsc_env mod_summary iface
+        ; if recomp then return outOfDate else do {
+
        -- Source code unchanged and no errors yet... carry on 
 
        -- First put the dependent-module info, read from the old interface, into the envt, 
@@ -900,16 +1072,63 @@ checkVersions hsc_env source_unchanged iface
        -- We do this regardless of compilation mode, although in --make mode
        -- all the dependent modules should be in the HPT already, so it's
        -- quite redundant
-       ; updateEps_ $ \eps  -> eps { eps_is_boot = mod_deps }
+         updateEps_ $ \eps  -> eps { eps_is_boot = mod_deps }
 
        ; let this_pkg = thisPackage (hsc_dflags hsc_env)
        ; checkList [checkModUsage this_pkg u | u <- mi_usages iface]
-    }
+    }}
   where
        -- This is a bit of a hack really
     mod_deps :: ModuleNameEnv (ModuleName, IsBootInterface)
     mod_deps = mkModDeps (dep_mods (mi_deps iface))
 
+
+-- If the direct imports of this module are resolved to targets that
+-- are not among the dependencies of the previous interface file,
+-- then we definitely need to recompile.  This catches cases like
+--   - an exposed package has been upgraded
+--   - we are compiling with different package flags
+--   - a home module that was shadowing a package module has been removed
+--   - a new home module has been added that shadows a package module
+-- See bug #1372.
+--
+-- Returns True if recompilation is required.
+checkDependencies :: HscEnv -> ModSummary -> ModIface -> IfG RecompileRequired
+checkDependencies hsc_env summary iface
+ = orM (map dep_missing (ms_imps summary ++ ms_srcimps summary))
+  where
+   prev_dep_mods = dep_mods (mi_deps iface)
+   prev_dep_pkgs = dep_pkgs (mi_deps iface)
+
+   this_pkg = thisPackage (hsc_dflags hsc_env)
+
+   orM = foldr f (return False)
+    where f m rest = do b <- m; if b then return True else rest
+
+   dep_missing (L _ mod) = do
+     find_res <- liftIO $ findImportedModule hsc_env mod Nothing
+     case find_res of
+        Found _ mod
+          | pkg == this_pkg
+           -> if moduleName mod `notElem` map fst prev_dep_mods
+                 then do traceHiDiffs $
+                           text "imported module " <> quotes (ppr mod) <>
+                           text " not among previous dependencies"
+                         return outOfDate
+                 else
+                         return upToDate
+          | otherwise
+           -> if pkg `notElem` prev_dep_pkgs
+                 then do traceHiDiffs $
+                           text "imported module " <> quotes (ppr mod) <>
+                           text " is from package " <> quotes (ppr pkg) <>
+                           text ", which is not among previous dependencies"
+                         return outOfDate
+                 else
+                         return upToDate
+           where pkg = modulePackageId mod
+        _otherwise  -> return outOfDate
+
 checkModUsage :: PackageId ->Usage -> IfG RecompileRequired
 -- Given the usage information extracted from the old
 -- M.hi file for the module being compiled, figure out
@@ -919,16 +1138,13 @@ checkModUsage this_pkg (Usage { usg_name = mod_name, usg_mod = old_mod_vers,
                                usg_rules = old_rule_vers,
                                usg_exports = maybe_old_export_vers, 
                                usg_entities = old_decl_vers })
-  =    -- Load the imported interface is possible
-    let
-       doc_str = sep [ptext SLIT("need version info for"), ppr mod_name]
-    in
-    traceHiDiffs (text "Checking usages for module" <+> ppr mod_name) `thenM_`
+  = do -- Load the imported interface is possible
+    let doc_str = sep [ptext SLIT("need version info for"), ppr mod_name]
+    traceHiDiffs (text "Checking usages for module" <+> ppr mod_name)
 
-    let
-       mod = mkModule this_pkg mod_name
-    in
-    loadInterface doc_str mod ImportBySystem           `thenM` \ mb_iface ->
+    let mod = mkModule this_pkg mod_name
+
+    mb_iface <- loadInterface doc_str mod ImportBySystem
        -- Load the interface, but don't complain on failure;
        -- Instead, get an Either back which we can test
 
@@ -947,9 +1163,9 @@ checkModUsage this_pkg (Usage { usg_name = mod_name, usg_mod = old_mod_vers,
        new_rule_vers   = mi_rule_vers iface
     in
        -- CHECK MODULE
-    checkModuleVersion old_mod_vers new_mod_vers       `thenM` \ recompile ->
+    checkModuleVersion old_mod_vers new_mod_vers       >>= \ recompile ->
     if not recompile then
-       returnM upToDate
+       return upToDate
     else
                                 
        -- CHECK EXPORT LIST
@@ -966,9 +1182,9 @@ checkModUsage this_pkg (Usage { usg_name = mod_name, usg_mod = old_mod_vers,
     else
 
        -- CHECK ITEMS ONE BY ONE
-    checkList [checkEntityUsage new_decl_vers u | u <- old_decl_vers]  `thenM` \ recompile ->
+    checkList [checkEntityUsage new_decl_vers u | u <- old_decl_vers]  >>= \ recompile ->
     if recompile then
-       returnM outOfDate       -- This one failed, so just bail out now
+       return outOfDate        -- This one failed, so just bail out now
     else
        up_to_date (ptext SLIT("  Great!  The bits I use are up to date"))
     }
@@ -994,25 +1210,24 @@ checkEntityUsage new_vers (name,old_vers)
                          out_of_date (sep [ptext SLIT("No longer exported:"), ppr name])
 
        Just (_, new_vers)      -- It's there, but is it up to date?
-         | new_vers == old_vers -> traceHiDiffs (text "  Up to date" <+> ppr name <+> parens (ppr new_vers)) `thenM_`
-                                   returnM upToDate
+         | new_vers == old_vers -> do traceHiDiffs (text "  Up to date" <+> ppr name <+> parens (ppr new_vers))
+                                      return upToDate
          | otherwise            -> out_of_date_vers (ptext SLIT("  Out of date:") <+> ppr name)
                                                     old_vers new_vers
 
-up_to_date  msg = traceHiDiffs msg `thenM_` returnM upToDate
-out_of_date msg = traceHiDiffs msg `thenM_` returnM outOfDate
+up_to_date  msg = traceHiDiffs msg >> return upToDate
+out_of_date msg = traceHiDiffs msg >> return outOfDate
 out_of_date_vers msg old_vers new_vers 
   = out_of_date (hsep [msg, ppr old_vers, ptext SLIT("->"), ppr new_vers])
 
 ----------------------
 checkList :: [IfG RecompileRequired] -> IfG RecompileRequired
 -- This helper is used in two places
-checkList []            = returnM upToDate
-checkList (check:checks) = check       `thenM` \ recompile ->
-                          if recompile then 
-                               returnM outOfDate
-                          else
-                               checkList checks
+checkList []            = return upToDate
+checkList (check:checks) = do recompile <- check
+                              if recompile
+                                then return outOfDate
+                                else checkList checks
 \end{code}
 
 %************************************************************************
@@ -1065,10 +1280,12 @@ tyThingToIfaceDecl (AClass clas)
 
 tyThingToIfaceDecl (ATyCon tycon)
   | isSynTyCon tycon
-  = IfaceSyn { ifName   = getOccName tycon,
-               ifTyVars = toIfaceTvBndrs tyvars,
+  = IfaceSyn { ifName    = getOccName tycon,
+               ifTyVars  = toIfaceTvBndrs tyvars,
                ifOpenSyn = syn_isOpen,
-               ifSynRhs  = toIfaceType syn_tyki }
+               ifSynRhs  = toIfaceType syn_tyki,
+                ifFamInst = famInstToIface (tyConFamInst_maybe tycon)
+             }
 
   | isAlgTyCon tycon
   = IfaceData {        ifName    = getOccName tycon,
@@ -1088,16 +1305,15 @@ tyThingToIfaceDecl (ATyCon tycon)
   where
     tyvars = tyConTyVars tycon
     (syn_isOpen, syn_tyki) = case synTyConRhs tycon of
-                              OpenSynTyCon ki -> (True , ki)
-                              SynonymTyCon ty -> (False, ty)
+                              OpenSynTyCon ki _ -> (True , ki)
+                              SynonymTyCon ty   -> (False, ty)
 
-    ifaceConDecls (NewTyCon { data_con = con })    = 
+    ifaceConDecls (NewTyCon { data_con = con })     = 
       IfNewTyCon  (ifaceConDecl con)
-    ifaceConDecls (DataTyCon { data_cons = cons }) = 
+    ifaceConDecls (DataTyCon { data_cons = cons })  = 
       IfDataTyCon (map ifaceConDecl cons)
-    ifaceConDecls OpenDataTyCon                    = IfOpenDataTyCon
-    ifaceConDecls OpenNewTyCon                     = IfOpenNewTyCon
-    ifaceConDecls AbstractTyCon                           = IfAbstractTyCon
+    ifaceConDecls OpenTyCon {}                      = IfOpenDataTyCon
+    ifaceConDecls AbstractTyCon                            = IfAbstractTyCon
        -- The last case happens when a TyCon has been trimmed during tidying
        -- Furthermore, tyThingToIfaceDecl is also used
        -- in TcRnDriver for GHCi, when browsing a module, in which case the
@@ -1109,7 +1325,7 @@ tyThingToIfaceDecl (ATyCon tycon)
                    ifConUnivTvs = toIfaceTvBndrs (dataConUnivTyVars data_con),
                    ifConExTvs   = toIfaceTvBndrs (dataConExTyVars data_con),
                    ifConEqSpec  = to_eq_spec (dataConEqSpec data_con),
-                   ifConCtxt    = toIfaceContext (dataConTheta data_con),
+                   ifConCtxt    = toIfaceContext (dataConEqTheta data_con ++ dataConDictTheta data_con),
                    ifConArgTys  = map toIfaceType (dataConOrigArgTys data_con),
                    ifConFields  = map getOccName 
                                       (dataConFieldLabels data_con),
@@ -1130,17 +1346,42 @@ getFS x = occNameFS (getOccName x)
 --------------------------
 instanceToIfaceInst :: Instance -> IfaceInst
 instanceToIfaceInst ispec@(Instance { is_dfun = dfun_id, is_flag = oflag,
-                                     is_cls = cls, is_tcs = mb_tcs, 
-                                     is_orph = orph })
-  = IfaceInst { ifDFun    = getName dfun_id,
+                                     is_cls = cls_name, is_tcs = mb_tcs })
+  = ASSERT( cls_name == className cls )
+    IfaceInst { ifDFun    = dfun_name,
                ifOFlag   = oflag,
-               ifInstCls = cls,
+               ifInstCls = cls_name,
                ifInstTys = map do_rough mb_tcs,
                ifInstOrph = orph }
   where
     do_rough Nothing  = Nothing
     do_rough (Just n) = Just (toIfaceTyCon_name n)
 
+    dfun_name = idName dfun_id
+    mod       = nameModule dfun_name
+    is_local name = nameIsLocalOrFrom mod name
+
+       -- Compute orphanhood.  See Note [Orphans] in IfaceSyn
+    (_, _, cls, tys) = tcSplitDFunTy (idType dfun_id)
+               -- Slightly awkward: we need the Class to get the fundeps
+    (tvs, fds) = classTvsFds cls
+    arg_names = [filterNameSet is_local (tyClsNamesOfType ty) | ty <- tys]
+    orph | is_local cls_name = Just (nameOccName cls_name)
+        | all isJust mb_ns  = head mb_ns
+        | otherwise         = Nothing
+    
+    mb_ns :: [Maybe OccName]   -- One for each fundep; a locally-defined name
+                               -- that is not in the "determined" arguments
+    mb_ns | null fds   = [choose_one arg_names]
+         | otherwise  = map do_one fds
+    do_one (ltvs,rtvs) = choose_one [ns | (tv,ns) <- tvs `zip` arg_names
+                                       , not (tv `elem` rtvs)]
+
+    choose_one :: [NameSet] -> Maybe OccName
+    choose_one nss = case nameSetToList (unionManyNameSets nss) of
+                       []     -> Nothing
+                       (n:ns) -> Just (nameOccName n)
+
 --------------------------
 famInstToIfaceFamInst :: FamInst -> IfaceFamInst
 famInstToIfaceFamInst fi@(FamInst { fi_tycon = tycon,
@@ -1153,6 +1394,22 @@ famInstToIfaceFamInst fi@(FamInst { fi_tycon = tycon,
     do_rough (Just n) = Just (toIfaceTyCon_name n)
 
 --------------------------
+toIfaceLetBndr id  = IfLetBndr (occNameFS (getOccName id))
+                              (toIfaceType (idType id)) 
+                              prag_info
+  where
+       -- Stripped-down version of tcIfaceIdInfo
+       -- Change this if you want to export more IdInfo for
+       -- non-top-level Ids.  Don't forget to change
+       -- CoreTidy.tidyLetBndr too!
+       --
+       -- See Note [IdInfo on nested let-bindings] in IfaceSyn
+    id_info = idInfo id
+    inline_prag = inlinePragInfo id_info
+    prag_info | isAlwaysActive inline_prag = NoInfo
+             | otherwise                  = HasInfo [HsInline inline_prag]
+
+--------------------------
 toIfaceIdInfo :: IdInfo -> [IfaceInfoItem]
 toIfaceIdInfo id_info
   = catMaybes [arity_hsinfo, caf_hsinfo, strict_hsinfo, 
@@ -1177,7 +1434,7 @@ toIfaceIdInfo id_info
 
     ------------  Worker  --------------
     work_info   = workerInfo id_info
-    has_worker  = case work_info of { HasWorker _ _ -> True; other -> False }
+    has_worker  = workerExists work_info
     wrkr_hsinfo = case work_info of
                    HasWorker work_id wrap_arity -> 
                        Just (HsWorker ((idName work_id)) wrap_arity)
@@ -1204,14 +1461,14 @@ toIfaceIdInfo id_info
                  | otherwise                      = Just (HsInline inline_prag)
 
 --------------------------
-coreRuleToIfaceRule :: CoreRule -> IfaceRule
-coreRuleToIfaceRule (BuiltinRule { ru_fn = fn})
+coreRuleToIfaceRule :: Module -> CoreRule -> IfaceRule
+coreRuleToIfaceRule mod (BuiltinRule { ru_fn = fn})
   = pprTrace "toHsRule: builtin" (ppr fn) $
     bogusIfaceRule fn
 
-coreRuleToIfaceRule (Rule { ru_name = name, ru_fn = fn, 
-                            ru_act = act, ru_bndrs = bndrs,
-                           ru_args = args, ru_rhs = rhs, ru_orph = orph })
+coreRuleToIfaceRule mod (Rule { ru_name = name, ru_fn = fn, 
+                                ru_act = act, ru_bndrs = bndrs,
+                               ru_args = args, ru_rhs = rhs })
   = IfaceRule { ifRuleName  = name, ifActivation = act, 
                ifRuleBndrs = map toIfaceBndr bndrs,
                ifRuleHead  = fn, 
@@ -1226,6 +1483,17 @@ coreRuleToIfaceRule (Rule { ru_name = name, ru_fn = fn,
     do_arg (Type ty) = IfaceType (toIfaceType (deNoteType ty))
     do_arg arg       = toIfaceExpr arg
 
+       -- Compute orphanhood.  See Note [Orphans] in IfaceSyn
+       -- A rule is an orphan only if none of the variables
+       -- mentioned on its left-hand side are locally defined
+    lhs_names = fn : nameSetToList (exprsFreeNames args)
+               -- No need to delete bndrs, because
+               -- exprsFreeNames finds only External names
+
+    orph = case filter (nameIsLocalOrFrom mod) lhs_names of
+                       (n:ns) -> Just (nameOccName n)
+                       []     -> Nothing
+
 bogusIfaceRule :: Name -> IfaceRule
 bogusIfaceRule id_name
   = IfaceRule { ifRuleName = FSLIT("bogus"), ifActivation = NeverActive,  
@@ -1250,8 +1518,8 @@ toIfaceNote InlineMe      = IfaceInlineMe
 toIfaceNote (CoreNote s)  = IfaceCoreNote s
 
 ---------------------
-toIfaceBind (NonRec b r) = IfaceNonRec (toIfaceIdBndr b) (toIfaceExpr r)
-toIfaceBind (Rec prs)    = IfaceRec [(toIfaceIdBndr b, toIfaceExpr r) | (b,r) <- prs]
+toIfaceBind (NonRec b r) = IfaceNonRec (toIfaceLetBndr b) (toIfaceExpr r)
+toIfaceBind (Rec prs)    = IfaceRec [(toIfaceLetBndr b, toIfaceExpr r) | (b,r) <- prs]
 
 ---------------------
 toIfaceAlt (c,bs,r) = (toIfaceCon c, map getFS bs, toIfaceExpr r)
@@ -1290,6 +1558,8 @@ toIfaceVar v
   | Just fcall <- isFCallId_maybe v = IfaceFCall fcall (toIfaceType (idType v))
          -- Foreign calls have special syntax
   | isExternalName name                    = IfaceExt name
+  | Just (TickBox m ix) <- isTickBoxOp_maybe v
+                                   = IfaceTick m ix
   | otherwise                      = IfaceLcl (getFS name)
   where
     name = idName v