Commit 2a67fb39 authored by Simon Peyton Jones's avatar Simon Peyton Jones
Browse files

Minor refactoring of Edward's recent orphans patch (Trac #2182)

This patch is all small stuff
  - Move VisibleOrphanModules from Module to InstEnv (with the other orphan stuff)
  - Move Notes about orphans from IfaceSyn to InstEnv (ditto)
  - Make use of the record field names in InstEnvs
parent 30d26058
......@@ -72,7 +72,7 @@ module Module
ModuleNameEnv,
-- * Sets of Modules
ModuleSet, VisibleOrphanModules,
ModuleSet,
emptyModuleSet, mkModuleSet, moduleSetElts, extendModuleSet, elemModuleSet
) where
......@@ -511,10 +511,5 @@ UniqFM.
\begin{code}
-- | A map keyed off of 'ModuleName's (actually, their 'Unique's)
type ModuleNameEnv elt = UniqFM elt
-- | Set of visible orphan modules, according to what modules have been directly
-- imported. This is based off of the dep_orphs field, which records
-- transitively reachable orphan modules (modules that define orphan instances).
type VisibleOrphanModules = ModuleSet
\end{code}
......@@ -214,7 +214,7 @@ data IfaceClsInst
ifInstTys :: [Maybe IfaceTyCon], -- the defn of ClsInst
ifDFun :: IfExtName, -- The dfun
ifOFlag :: OverlapFlag, -- Overlap flag
ifInstOrph :: IsOrphan } -- See Note [Orphans]
ifInstOrph :: IsOrphan } -- See Note [Orphans] in InstEnv
-- There's always a separate IfaceDecl for the DFun, which gives
-- its IdInfo with its full type and version number.
-- The instance declarations taken together have a version number,
......@@ -228,7 +228,7 @@ data IfaceFamInst
= IfaceFamInst { ifFamInstFam :: IfExtName -- Family name
, ifFamInstTys :: [Maybe IfaceTyCon] -- See above
, ifFamInstAxiom :: IfExtName -- The axiom
, ifFamInstOrph :: IsOrphan -- Just like IfaceClsInst
, ifFamInstOrph :: IsOrphan -- Just like IfaceClsInst
}
data IfaceRule
......@@ -303,77 +303,6 @@ data IfaceIdDetails
\end{code}
Note [Orphans]: the ifInstOrph and ifRuleOrph fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Class instances, rules, and family instances are divided into orphans
and non-orphans. Roughly speaking, an instance/rule is an orphan if
its left hand side mentions nothing defined in this module. Orphan-hood
has two major consequences
* A non-orphan is not finger-printed separately. Instead, for
fingerprinting purposes it is treated as part of the entity it
mentions on the LHS. For example
data T = T1 | T2
instance Eq T where ....
The instance (Eq T) is incorprated as part of T's fingerprint.
In constrast, orphans are all fingerprinted together in the
mi_orph_hash field of the ModIface.
See MkIface.addFingerprints.
* A module that contains orphans is called an "orphan module". If
the module being compiled depends (transitively) on an oprhan
module M, then M.hi is read in regardless of whether M is oherwise
needed. This is to ensure that we don't miss any instance decls in
M. But it's painful, because it means we need to keep track of all
the orphan modules below us.
Orphan-hood is computed when we generate an IfaceInst, IfaceRule, or
IfaceFamInst respectively:
- If an instance is an orphan its ifInstOprh field is Nothing
Otherwise ifInstOrph is (Just n) where n is the Name of a
local class or tycon that witnesses its non-orphan-hood.
This computation is done by MkIface.instanceToIfaceInst
- Similarly for ifRuleOrph
The computation is done by MkIface.coreRuleToIfaceRule
Note [When exactly is an instance decl an orphan?]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(see MkIface.instanceToIfaceInst, which implements this)
Roughly speaking, an instance is an orphan if its head (after the =>)
mentions nothing defined in this module.
Functional dependencies complicate the situation though. Consider
module M where { class C a b | a -> b }
and suppose we are compiling module X:
module X where
import M
data T = ...
instance C Int T where ...
This instance is an orphan, because when compiling a third module Y we
might get a constraint (C Int v), and we'd want to improve v to T. So
we must make sure X's instances are loaded, even if we do not directly
use anything from X.
More precisely, an instance is an orphan iff
If there are no fundeps, then at least of the names in
the instance head is locally defined.
If there are fundeps, then for every fundep, at least one of the
names free in a *non-determined* part of the instance head is
defined in this module.
(Note that these conditions hold trivially if the class is locally
defined.)
Note [Versioning of instances]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See [http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance#Instances]
......
......@@ -744,7 +744,7 @@ data IfaceDeclExtras
| IfaceDataExtras
Fixity -- Fixity of the tycon itself
[IfaceInstABI] -- Local class and family instances of this tycon
-- See Note [Orphans] in IfaceSyn
-- See Note [Orphans] in InstEnv
[AnnPayload] -- Annotations of the type itself
[IfaceIdExtras] -- For each constructor: fixity, RULES and annotations
......@@ -752,7 +752,7 @@ data IfaceDeclExtras
Fixity -- Fixity of the class itself
[IfaceInstABI] -- Local instances of this class *or*
-- of its associated data types
-- See Note [Orphans] in IfaceSyn
-- See Note [Orphans] in InstEnv
[AnnPayload] -- Annotations of the type itself
[IfaceIdExtras] -- For each class method: fixity, RULES and annotations
......@@ -1948,7 +1948,7 @@ coreRuleToIfaceRule mod rule@(Rule { ru_name = name, ru_fn = fn,
do_arg (Coercion co) = IfaceCo (toIfaceCoercion co)
do_arg arg = toIfaceExpr arg
-- Compute orphanhood. See Note [Orphans] in IfaceSyn
-- Compute orphanhood. See Note [Orphans] in InstEnv
-- A rule is an orphan only if none of the variables
-- mentioned on its left-hand side are locally defined
lhs_names = nameSetElems (ruleLhsOrphNames rule)
......
......@@ -398,15 +398,6 @@ getOverlapFlag overlap_mode
final_oflag = setOverlapModeMaybe default_oflag overlap_mode
; return final_oflag }
tcGetInstEnvs :: TcM InstEnvs
-- Gets both the external-package inst-env
-- and the home-pkg inst env (includes module being compiled)
tcGetInstEnvs = do { eps <- getEps
; env <- getGblEnv
; return (InstEnvs (eps_inst_env eps)
(tcg_inst_env env)
(tcg_visible_orphan_mods env))}
tcGetInsts :: TcM [ClsInst]
-- Gets the local class instances.
tcGetInsts = fmap tcg_insts getGblEnv
......@@ -485,9 +476,9 @@ addLocalInst (home_ie, my_insts) ispec
global_ie
| isJust (tcg_sig_of tcg_env) = emptyInstEnv
| otherwise = eps_inst_env eps
inst_envs = InstEnvs global_ie
home_ie'
(tcg_visible_orphan_mods tcg_env)
inst_envs = InstEnvs { ie_global = global_ie
, ie_local = home_ie'
, ie_visible = tcg_visible_orphan_mods tcg_env }
(matches, _, _) = lookupInstEnv inst_envs cls tys
dups = filter (identicalInstHead ispec) (map fst matches)
......
......@@ -21,7 +21,7 @@ module TcEnv(
tcLookupField, tcLookupTyCon, tcLookupClass,
tcLookupDataCon, tcLookupPatSyn, tcLookupConLike,
tcLookupLocatedGlobalId, tcLookupLocatedTyCon,
tcLookupLocatedClass, tcLookupInstance, tcLookupAxiom,
tcLookupLocatedClass, tcLookupAxiom,
-- Local environment
tcExtendKindEnv, tcExtendKindEnv2,
......@@ -38,8 +38,11 @@ module TcEnv(
tcExtendRecEnv, -- For knot-tying
-- Instances
tcLookupInstance, tcGetInstEnvs,
-- Rules
tcExtendRules,
tcExtendRules,
-- Defaults
tcGetDefaultTys,
......@@ -225,12 +228,14 @@ tcLookupInstance cls tys
extractTyVar (TyVarTy tv) = tv
extractTyVar _ = panic "TcEnv.tcLookupInstance: extractTyVar"
-- NB: duplicated to prevent circular dependence on Inst
tcGetInstEnvs = do { eps <- getEps
; env <- getGblEnv
; return (InstEnvs (eps_inst_env eps)
(tcg_inst_env env)
(tcg_visible_orphan_mods env)) }
tcGetInstEnvs :: TcM InstEnvs
-- Gets both the external-package inst-env
-- and the home-pkg inst env (includes module being compiled)
tcGetInstEnvs = do { eps <- getEps
; env <- getGblEnv
; return (InstEnvs { ie_global = eps_inst_env eps
, ie_local = tcg_inst_env env
, ie_visible = tcg_visible_orphan_mods env }) }
\end{code}
\begin{code}
......
......@@ -79,7 +79,6 @@ import DataCon
import Type
import Class
import CoAxiom
import Inst ( tcGetInstEnvs )
import Annotations
import Data.List ( sortBy )
import Data.Ord
......@@ -1974,7 +1973,7 @@ tcRnGetInfo hsc_env name
lookupInsts :: TyThing -> TcM ([ClsInst],[FamInst])
lookupInsts (ATyCon tc)
= do { InstEnvs pkg_ie home_ie vis_mods <- tcGetInstEnvs
= do { InstEnvs { ie_global = pkg_ie, ie_local = home_ie, ie_visible = vis_mods } <- tcGetInstEnvs
; (pkg_fie, home_fie) <- tcGetFamInstEnvs
-- Load all instances for all classes that are
-- in the type environment (which are all the ones
......
......@@ -273,6 +273,7 @@ data TcGblEnv
-- ^ The set of orphan modules which transitively reachable from
-- direct imports. We use this to figure out if an orphan instance
-- in the global InstEnv should be considered visible.
-- See Note [Instance lookup and orphan instances] in InstEnv
-- Now a bunch of things about this module that are simply
-- accumulated, but never consulted until the end.
......
This diff is collapsed.
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