+++ /dev/null
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1999
-%
-
-Analysis functions over data types. Specficially
- a) detecting recursive types
- b) computing argument variances
-
-This stuff is only used for source-code decls; it's recorded in interface
-files for imported data types.
-
-
-\begin{code}
-module TcTyDecls(
- calcTyConArgVrcs,
- calcRecFlags,
- calcClassCycles, calcSynCycles
- ) where
-
-#include "HsVersions.h"
-
-import TypeRep ( Type(..), TyNote(..), PredType(..) ) -- friend
-import HsSyn ( TyClDecl(..), HsPred(..), LTyClDecl, isClassDecl )
-import RnHsSyn ( extractHsTyNames )
-import Type ( predTypeRep, tcView )
-import HscTypes ( TyThing(..), ModDetails(..) )
-import TyCon ( TyCon, ArgVrcs, tyConArity, tyConDataCons, tyConTyVars,
- synTyConDefn, isSynTyCon, isAlgTyCon,
- tyConName, isNewTyCon, isProductTyCon, tyConArgVrcs, newTyConRhs )
-import Class ( classTyCon )
-import DataCon ( dataConOrigArgTys )
-import Var ( TyVar )
-import VarSet
-import Name ( Name, isTyVarName )
-import NameEnv
-import NameSet
-import Digraph ( SCC(..), stronglyConnComp, stronglyConnCompR )
-import BasicTypes ( RecFlag(..) )
-import SrcLoc ( Located(..), unLoc )
-import Outputable
-\end{code}
-
-
-%************************************************************************
-%* *
- Cycles in class and type synonym declarations
-%* *
-%************************************************************************
-
-Checking for class-decl loops is easy, because we don't allow class decls
-in interface files.
-
-We allow type synonyms in hi-boot files, but we *trust* hi-boot files,
-so we don't check for loops that involve them. So we only look for synonym
-loops in the module being compiled.
-
-We check for type synonym and class cycles on the *source* code.
-Main reasons:
-
- a) Otherwise we'd need a special function to extract type-synonym tycons
- from a type, whereas we have extractHsTyNames already
-
- b) If we checked for type synonym loops after building the TyCon, we
- can't do a hoistForAllTys on the type synonym rhs, (else we fall into
- a black hole) which seems unclean. Apart from anything else, it'd mean
- that a type-synonym rhs could have for-alls to the right of an arrow,
- which means adding new cases to the validity checker
-
- Indeed, in general, checking for cycles beforehand means we need to
- be less careful about black holes through synonym cycles.
-
-The main disadvantage is that a cycle that goes via a type synonym in an
-.hi-boot file can lead the compiler into a loop, because it assumes that cycles
-only occur entirely within the source code of the module being compiled.
-But hi-boot files are trusted anyway, so this isn't much worse than (say)
-a kind error.
-
-[ NOTE ----------------------------------------------
-If we reverse this decision, this comment came from tcTyDecl1, and should
- go back there
- -- dsHsType, not tcHsKindedType, to avoid a loop. tcHsKindedType does hoisting,
- -- which requires looking through synonyms... and therefore goes into a loop
- -- on (erroneously) recursive synonyms.
- -- Solution: do not hoist synonyms, because they'll be hoisted soon enough
- -- when they are substituted
-
-We'd also need to add back in this definition
-
-synTyConsOfType :: Type -> [TyCon]
--- Does not look through type synonyms at all
--- Return a list of synonym tycons
-synTyConsOfType ty
- = nameEnvElts (go ty)
- where
- go :: Type -> NameEnv TyCon -- The NameEnv does duplicate elim
- go (TyVarTy v) = emptyNameEnv
- go (TyConApp tc tys) = go_tc tc tys
- go (AppTy a b) = go a `plusNameEnv` go b
- go (FunTy a b) = go a `plusNameEnv` go b
- go (PredTy (IParam _ ty)) = go ty
- go (PredTy (ClassP cls tys)) = go_s tys -- Ignore class
- go (NoteTy _ ty) = go ty
- go (ForAllTy _ ty) = go ty
-
- go_tc tc tys | isSynTyCon tc = extendNameEnv (go_s tys) (tyConName tc) tc
- | otherwise = go_s tys
- go_s tys = foldr (plusNameEnv . go) emptyNameEnv tys
----------------------------------------- END NOTE ]
-
-\begin{code}
-calcSynCycles :: [LTyClDecl Name] -> [SCC (LTyClDecl Name)]
-calcSynCycles decls
- = stronglyConnComp syn_edges
- where
- syn_edges = [ (ldecl, unLoc (tcdLName decl),
- mk_syn_edges (tcdSynRhs decl))
- | ldecl@(L _ decl) <- decls ]
-
- mk_syn_edges rhs = [ tc | tc <- nameSetToList (extractHsTyNames rhs),
- not (isTyVarName tc) ]
-
-
-calcClassCycles :: [LTyClDecl Name] -> [[LTyClDecl Name]]
-calcClassCycles decls
- = [decls | CyclicSCC decls <- stronglyConnComp cls_edges]
- where
- cls_edges = [ (ldecl, unLoc (tcdLName decl),
- mk_cls_edges (unLoc (tcdCtxt decl)))
- | ldecl@(L _ decl) <- decls, isClassDecl decl ]
-
- mk_cls_edges ctxt = [ cls | L _ (HsClassP cls _) <- ctxt ]
-\end{code}
-
-
-%************************************************************************
-%* *
- Deciding which type constructors are recursive
-%* *
-%************************************************************************
-
-For newtypes, we label some as "recursive" such that
-
- INVARIANT: there is no cycle of non-recursive newtypes
-
-In any loop, only one newtype need be marked as recursive; it is
-a "loop breaker". Labelling more than necessary as recursive is OK,
-provided the invariant is maintained.
-
-A newtype M.T is defined to be "recursive" iff
- (a) it is declared in an hi-boot file (see RdrHsSyn.hsIfaceDecl)
- (b) it is declared in a source file, but that source file has a
- companion hi-boot file which declares the type
- or (c) one can get from T's rhs to T via type
- synonyms, or non-recursive newtypes *in M*
- e.g. newtype T = MkT (T -> Int)
-
-(a) is conservative; declarations in hi-boot files are always
- made loop breakers. That's why in (b) we can restrict attention
- to tycons in M, because any loops through newtypes outside M
- will be broken by those newtypes
-(b) ensures that a newtype is not treated as a loop breaker in one place
-and later as a non-loop-breaker. This matters in GHCi particularly, when
-a newtype T might be embedded in many types in the environment, and then
-T's source module is compiled. We don't want T's recursiveness to change.
-
-The "recursive" flag for algebraic data types is irrelevant (never consulted)
-for types with more than one constructor.
-
-An algebraic data type M.T is "recursive" iff
- it has just one constructor, and
- (a) it is declared in an hi-boot file (see RdrHsSyn.hsIfaceDecl)
- (b) it is declared in a source file, but that source file has a
- companion hi-boot file which declares the type
- or (c) one can get from its arg types to T via type synonyms,
- or by non-recursive newtypes or non-recursive product types in M
- e.g. data T = MkT (T -> Int) Bool
-Just like newtype in fact
-
-A type synonym is recursive if one can get from its
-right hand side back to it via type synonyms. (This is
-reported as an error.)
-
-A class is recursive if one can get from its superclasses
-back to it. (This is an error too.)
-
-Hi-boot types
-~~~~~~~~~~~~~
-A data type read from an hi-boot file will have an AbstractTyCon as its AlgTyConRhs
-and will respond True to isHiBootTyCon. The idea is that we treat these as if one
-could get from these types to anywhere. So when we see
-
- module Baz where
- import {-# SOURCE #-} Foo( T )
- newtype S = MkS T
-
-then we mark S as recursive, just in case. What that means is that if we see
-
- import Baz( S )
- newtype R = MkR S
-
-then we don't need to look inside S to compute R's recursiveness. Since S is imported
-(not from an hi-boot file), one cannot get from R back to S except via an hi-boot file,
-and that means that some data type will be marked recursive along the way. So R is
-unconditionly non-recursive (i.e. there'll be a loop breaker elsewhere if necessary)
-
-This in turn means that we grovel through fewer interface files when computing
-recursiveness, because we need only look at the type decls in the module being
-compiled, plus the outer structure of directly-mentioned types.
-
-\begin{code}
-calcRecFlags :: ModDetails -> [TyThing] -> (Name -> RecFlag)
--- The 'boot_names' are the things declared in M.hi-boot, if M is the current module.
--- Any type constructors in boot_names are automatically considered loop breakers
-calcRecFlags boot_details tyclss
- = is_rec
- where
- is_rec n | n `elemNameSet` rec_names = Recursive
- | otherwise = NonRecursive
-
- boot_name_set = md_exports boot_details
- rec_names = boot_name_set `unionNameSets`
- nt_loop_breakers `unionNameSets`
- prod_loop_breakers
-
- all_tycons = [ tc | tycls <- tyclss,
- -- Recursion of newtypes/data types can happen via
- -- the class TyCon, so tyclss includes the class tycons
- let tc = getTyCon tycls,
- not (tyConName tc `elemNameSet` boot_name_set) ]
- -- Remove the boot_name_set because they are going
- -- to be loop breakers regardless.
-
- -------------------------------------------------
- -- NOTE
- -- These edge-construction loops rely on
- -- every loop going via tyclss, the types and classes
- -- in the module being compiled. Stuff in interface
- -- files should be correctly marked. If not (e.g. a
- -- type synonym in a hi-boot file) we can get an infinite
- -- loop. We could program round this, but it'd make the code
- -- rather less nice, so I'm not going to do that yet.
-
- --------------- Newtypes ----------------------
- new_tycons = filter isNewTyCon all_tycons
- nt_loop_breakers = mkNameSet (findLoopBreakers nt_edges)
- is_rec_nt tc = tyConName tc `elemNameSet` nt_loop_breakers
- -- is_rec_nt is a locally-used helper function
-
- nt_edges = [(t, mk_nt_edges t) | t <- new_tycons]
-
- mk_nt_edges nt -- Invariant: nt is a newtype
- = concatMap (mk_nt_edges1 nt) (tcTyConsOfType (new_tc_rhs nt))
- -- tyConsOfType looks through synonyms
-
- mk_nt_edges1 nt tc
- | tc `elem` new_tycons = [tc] -- Loop
- -- At this point we know that either it's a local *data* type,
- -- or it's imported. Either way, it can't form part of a newtype cycle
- | otherwise = []
-
- --------------- Product types ----------------------
- -- The "prod_tycons" are the non-newtype products
- prod_tycons = [tc | tc <- all_tycons,
- not (isNewTyCon tc), isProductTyCon tc]
- prod_loop_breakers = mkNameSet (findLoopBreakers prod_edges)
-
- prod_edges = [(tc, mk_prod_edges tc) | tc <- prod_tycons]
-
- mk_prod_edges tc -- Invariant: tc is a product tycon
- = concatMap (mk_prod_edges1 tc) (dataConOrigArgTys (head (tyConDataCons tc)))
-
- mk_prod_edges1 ptc ty = concatMap (mk_prod_edges2 ptc) (tcTyConsOfType ty)
-
- mk_prod_edges2 ptc tc
- | tc `elem` prod_tycons = [tc] -- Local product
- | tc `elem` new_tycons = if is_rec_nt tc -- Local newtype
- then []
- else mk_prod_edges1 ptc (new_tc_rhs tc)
- -- At this point we know that either it's a local non-product data type,
- -- or it's imported. Either way, it can't form part of a cycle
- | otherwise = []
-
-new_tc_rhs tc = snd (newTyConRhs tc) -- Ignore the type variables
-
-getTyCon (ATyCon tc) = tc
-getTyCon (AClass cl) = classTyCon cl
-
-findLoopBreakers :: [(TyCon, [TyCon])] -> [Name]
--- Finds a set of tycons that cut all loops
-findLoopBreakers deps
- = go [(tc,tc,ds) | (tc,ds) <- deps]
- where
- go edges = [ name
- | CyclicSCC ((tc,_,_) : edges') <- stronglyConnCompR edges,
- name <- tyConName tc : go edges']
-\end{code}
-
-These two functions know about type representations, so they could be
-in Type or TcType -- but they are very specialised to this module, so
-I've chosen to put them here.
-
-\begin{code}
-tcTyConsOfType :: Type -> [TyCon]
--- tcTyConsOfType looks through all synonyms, but not through any newtypes.
--- When it finds a Class, it returns the class TyCon. The reaons it's here
--- (not in Type.lhs) is because it is newtype-aware.
-tcTyConsOfType ty
- = nameEnvElts (go ty)
- where
- go :: Type -> NameEnv TyCon -- The NameEnv does duplicate elim
- go ty | Just ty' <- tcView ty = go ty'
- go (TyVarTy v) = emptyNameEnv
- go (TyConApp tc tys) = go_tc tc tys
- go (AppTy a b) = go a `plusNameEnv` go b
- go (FunTy a b) = go a `plusNameEnv` go b
- go (PredTy (IParam _ ty)) = go ty
- go (PredTy (ClassP cls tys)) = go_tc (classTyCon cls) tys
- go (ForAllTy _ ty) = go ty
-
- go_tc tc tys = extendNameEnv (go_s tys) (tyConName tc) tc
- go_s tys = foldr (plusNameEnv . go) emptyNameEnv tys
-\end{code}
-
-
-%************************************************************************
-%* *
- Compuing TyCon argument variances
-%* *
-%************************************************************************
-
-Computing the tyConArgVrcs info
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-@tyConArgVrcs@ gives a list of (occPos,occNeg) flags, one for each
-tyvar. For @AlgTyCon@s and @SynTyCon@s, this info must be precomputed
-separately. Note that this is information about occurrences of type
-variables, not usages of term variables.
-
-The function @calcTyConArgVrcs@ must be passed a list of *algebraic or
-syntycons only* such that all tycons referred to (by mutual recursion)
-appear in the list. The fixpointing will be done on this set of
-tycons as a whole. It returns a list of @tyconVrcInfo@ data, ready to
-be (knot-tyingly?) stuck back into the appropriate fields.
-
-\begin{code}
-calcTyConArgVrcs :: [TyThing] -> Name -> ArgVrcs
--- Gives arg variances for TyCons,
--- including the class TyCon of a class
-calcTyConArgVrcs tyclss
- = get_vrc
- where
- tycons = map getTyCon tyclss
-
- -- We should only look up things that are in the map
- get_vrc n = case lookupNameEnv final_oi n of
- Just (_, pms) -> pms
- Nothing -> pprPanic "calcVrcs" (ppr n)
-
- -- We are going to fold over this map,
- -- so we need the TyCon in the range
- final_oi :: NameEnv (TyCon, ArgVrcs)
- final_oi = tcaoFix initial_oi
-
- initial_oi :: NameEnv (TyCon, ArgVrcs)
- initial_oi = mkNameEnv [(tyConName tc, (tc, initial tc))
- | tc <- tycons]
- initial tc = replicate (tyConArity tc) (False,False)
-
- tcaoFix :: NameEnv (TyCon, ArgVrcs) -- initial ArgVrcs per tycon
- -> NameEnv (TyCon, ArgVrcs) -- fixpointed ArgVrcs per tycon
- tcaoFix oi
- | changed = tcaoFix oi'
- | otherwise = oi'
- where
- (changed,oi') = foldNameEnv iterate (False,oi) oi
-
- iterate (tc, pms) (changed,oi')
- = (changed || (pms /= pms'),
- extendNameEnv oi' (tyConName tc) (tc, pms'))
- where
- pms' = tcaoIter oi' tc -- seq not simult
-
- tcaoIter :: NameEnv (TyCon, ArgVrcs) -- reference ArgVrcs (initial)
- -> TyCon -- tycon to update
- -> ArgVrcs -- new ArgVrcs for tycon
-
- tcaoIter oi tc | isAlgTyCon tc
- = map (\v -> anyVrc (vrcInTy (lookup oi) v) argtys) vs
- where
- data_cons = tyConDataCons tc
- vs = tyConTyVars tc
- argtys = concatMap dataConOrigArgTys data_cons -- Rep? or Orig?
-
- tcaoIter oi tc | isSynTyCon tc
- = let (tyvs,ty) = synTyConDefn tc
- -- we use the already-computed result for tycons not in this SCC
- in map (\v -> vrcInTy (lookup oi) v ty) tyvs
-
- lookup oi tc = case lookupNameEnv oi (tyConName tc) of
- Just (_, pms) -> pms
- Nothing -> tyConArgVrcs tc
- -- We use the already-computed result for tycons not in this SCC
-\end{code}
-
-
-Variance of tyvars in a type
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A general variance-check function. We pass a function for determining
-the @ArgVrc@s of a tycon; when fixpointing this refers to the current
-value; otherwise this should be looked up from the tycon's own
-tyConArgVrcs. Again, it knows the representation of Types.
-
-\begin{code}
-vrcInTy :: (TyCon -> ArgVrcs) -- function to get argVrcs of a tycon (break out of recursion)
- -> TyVar -- tyvar to check Vrcs of
- -> Type -- type to check for occ in
- -> (Bool,Bool) -- (occurs positively, occurs negatively)
-
-vrcInTy fao v (NoteTy (FTVNote ftv) ty) = if elemVarSet v ftv
- then vrcInTy fao v ty
- else (False,False)
- -- note that ftv cannot be calculated as occPos||occNeg,
- -- since if a tyvar occurs only as unused tyconarg,
- -- occPos==occNeg==False, but ftv=True
-
-vrcInTy fao v (TyVarTy v') = if v==v'
- then (True,False)
- else (False,False)
-
-vrcInTy fao v (AppTy ty1 ty2) = if vrcInTy fao v ty2 /= (False,False)
- then (True,True)
- else vrcInTy fao v ty1
- -- ty1 is probably unknown (or it would have been beta-reduced);
- -- hence if v occurs in ty2 at all then it could occur with
- -- either variance. Otherwise it occurs as it does in ty1.
-
-vrcInTy fao v (FunTy ty1 ty2) = negVrc (vrcInTy fao v ty1)
- `orVrc`
- vrcInTy fao v ty2
-
-vrcInTy fao v (ForAllTy v' ty) = if v==v'
- then (False,False)
- else vrcInTy fao v ty
-
-vrcInTy fao v (TyConApp tc tys) = let pms1 = map (vrcInTy fao v) tys
- pms2 = fao tc
- in orVrcs (zipWith timesVrc pms1 pms2)
-
-vrcInTy fao v (PredTy st) = vrcInTy fao v (predTypeRep st)
-\end{code}
-
-Variance algebra
-~~~~~~~~~~~~~~~~
-
-\begin{code}
-orVrc :: (Bool,Bool) -> (Bool,Bool) -> (Bool,Bool)
-orVrc (p1,m1) (p2,m2) = (p1||p2,m1||m2)
-
-orVrcs :: [(Bool,Bool)] -> (Bool,Bool)
-orVrcs = foldl orVrc (False,False)
-
-negVrc :: (Bool,Bool) -> (Bool,Bool)
-negVrc (p1,m1) = (m1,p1)
-
-anyVrc :: (a -> (Bool,Bool)) -> [a] -> (Bool,Bool)
-anyVrc p as = foldl (\ pm a -> pm `orVrc` p a)
- (False,False) as
-
-timesVrc :: (Bool,Bool) -> (Bool,Bool) -> (Bool,Bool)
-timesVrc (p1,m1) (p2,m2) = (p1 && p2 || m1 && m2,
- p1 && m2 || m1 && p2)
-\end{code}