lhc-0.6.20081127: src/FrontEnd/Tc/Module.hs
module FrontEnd.Tc.Module (tiModules',TiData(..)) where
import Char
import Control.Monad.Writer
import IO
import List
import Maybe
import Monad
import Text.PrettyPrint.ANSI.Leijen as PPrint
import qualified Data.Map as Map
import qualified Data.Set as Set
import FrontEnd.DataConsAssump (dataConsEnv)
import DataConstructors
import FrontEnd.DeclsDepends (getDeclDeps, debugDeclBindGroups)
import FrontEnd.DependAnalysis (getBindGroups)
import DerivingDrift.Drift
import Doc.PPrint as PPrint
import FrontEnd.Class
import FrontEnd.Desugar
import FrontEnd.Exports
import FrontEnd.Infix
import FrontEnd.KindInfer
import FrontEnd.Rename
import FrontEnd.Tc.Main
import FrontEnd.Tc.Monad
import FrontEnd.Tc.Type
import FrontEnd.Utils
import FrontEnd.Warning
import Ho.Type
import Ho.Collected
import FrontEnd.HsSyn
import Info.Types
import Name.Name as Name
import Options
import FrontEnd.TypeSigs (collectSigs, listSigsToSigEnv)
import FrontEnd.TypeSynonyms
import FrontEnd.TypeSyns
--import ClassAliases
import Util.Gen
import Util.Inst()
import Util.SetLike
import qualified FlagDump as FD
import qualified FrontEnd.HsPretty as HsPretty
trimEnv env = Map.filterWithKey (\k _ -> isGlobal k) env
getDeclNames :: HsDecl -> [Name]
getDeclNames (HsTypeSig _ ns _ ) = map (toName Val) ns
getDeclNames d = maybeGetDeclName d
-- Extra data produced by the front end, used to fill in the Ho file.
data TiData = TiData {
tiDataDecls :: [HsDecl],
tiDataModules :: [(Module,HsModule)],
tiModuleOptions :: [(Module,Opt)],
tiCheckedRules :: [Rule],
tiCoerce :: Map.Map Name CoerceTerm,
tiProps :: Map.Map Name Properties,
tiAllAssumptions :: Map.Map Name Type
}
isGlobal x | (_,(_::String,(h:_))) <- fromName x = not $ isDigit h
isGlobal _ = error "isGlobal"
render :: Doc -> String
render = show
buildFieldMap :: Ho -> [ModInfo] -> FieldMap
buildFieldMap ho ms = (ans',ans) where
theDefs = [ (x,z) | (x,_,z) <- concat $ map modInfoDefs ms, nameType x == DataConstructor ]
allDefs = theDefs ++ [ (x,z) | (x,(_,z)) <- Map.toList (hoDefs $ hoExp ho), nameType x == DataConstructor ]
ans = Map.fromList $ sortGroupUnderFG fst snd $ concat [ [ (y,(x,i)) | y <- ys | i <- [0..] ] | (x,ys) <- allDefs ]
ans' = Map.fromList $ concatMap modInfoConsArity ms ++ getConstructorArities (hoDataTable $ hoBuild ho)
processModule :: FieldMap -> ModInfo -> IO ModInfo
processModule defs m = do
when (dump FD.Parsed) $ do
putStrLn " \n ---- parsed code ---- \n";
putStrLn $ HsPretty.render
$ HsPretty.ppHsModule
$ modInfoHsModule m
-- driftDerive only uses IO to print the derived instances.
zmod' <- driftDerive (modInfoHsModule m)
let mod = desugarHsModule (zmod')
let (mod',errs) = runWriter $ renameModule defs (modInfoImport m) mod
when (dump FD.Renamed) $ do
putStrLn " \n ---- renamed code ---- \n"
putStrLn $ HsPretty.render $ HsPretty.ppHsModule $ mod'
processErrors errs
return $ modInfoHsModule_s mod' m
-- type check a set of mutually recursive modules.
-- assume all dependencies are met in the
-- ModEnv parameter and export lists have been calculated.
or' :: [(a -> Bool)] -> a -> Bool
or' fs x = or [ f x | f <- fs ]
-- FIXME: Use an warnings+writer+error monad instead of IO.
tiModules' :: CollectedHo -> [ModInfo] -> IO (Ho,TiData)
tiModules' cho ms = do
let me = choHo cho
hoB = hoBuild me
-- let importVarEnv = Map.fromList [ (x,y) | (x,y) <- Map.toList $ hoAssumps me, nameType x == Name.Val ]
-- importDConsEnv = Map.fromList [ (x,y) | (x,y) <- Map.toList $ hoAssumps me, nameType x == Name.DataConstructor ]
let importClassHierarchy = hoClassHierarchy hoB
importKindEnv = hoKinds hoB
wdump FD.Progress $ do
putErrLn $ "Typing: " ++ show ([ m | Module m <- map modInfoName ms])
let fieldMap = buildFieldMap me ms
-- 'processModule' doesn't need IO. We can use a plain writer+error monad.
ms <- mapM (processModule fieldMap) ms
let thisFixityMap = buildFixityMap (concat [ filter isHsInfixDecl (hsModuleDecls $ modInfoHsModule m) | m <- ms])
let fixityMap = thisFixityMap `mappend` hoFixities hoB
let thisTypeSynonyms = (declsToTypeSynonyms $ concat [ filter isHsTypeDecl (hsModuleDecls $ modInfoHsModule m) | m <- ms])
let ts = thisTypeSynonyms `mappend` hoTypeSynonyms hoB
-- 'expandTypeSyns' is in the Warning monad and doesn't require IO.
let f x = expandTypeSyns ts (modInfoHsModule x) >>= return . FrontEnd.Infix.infixHsModule fixityMap >>= \z -> return (modInfoHsModule_s ( z) x)
ms <- mapM f ms
processIOErrors
let ds = concat [ hsModuleDecls $ modInfoHsModule m | m <- ms ]
wdump FD.Decls $ do
putStrLn " ---- processed decls ---- "
putStrLn $ HsPretty.render (HsPretty.ppHsDecls ds)
-- kind inference for all type constructors type variables and classes in the module
let classAndDataDecls = filter (or' [isHsDataDecl, isHsNewTypeDecl, isHsClassDecl, isHsClassAliasDecl]) ds -- rDataDecls ++ rNewTyDecls ++ rClassDecls
wdump FD.Progress $ do
putErrLn $ "Kind inference"
kindInfo <- kiDecls importKindEnv classAndDataDecls
when (dump FD.Kind) $
do {putStrLn " \n ---- kind information ---- \n";
putStrLn $ render $ pprint kindInfo }
-- collect types for data constructors
let localDConsEnv = dataConsEnv (error "modName") kindInfo classAndDataDecls -- (rDataDecls ++ rNewTyDecls)
wdump FD.Dcons $ do
putStr "\n ---- data constructor assumptions ---- \n"
mapM_ putStrLn [ show n ++ " :: " ++ prettyPrintType s | (n,s) <- Map.toList localDConsEnv]
--let globalDConsEnv = localDConsEnv `Map.union` importDConsEnv
let smallClassHierarchy = makeClassHierarchy importClassHierarchy kindInfo ds
let cHierarchyWithInstances = scatterAliasInstances $ smallClassHierarchy `mappend` importClassHierarchy
when (dump FD.ClassSummary) $ do
putStrLn " ---- class summary ---- "
printClassSummary cHierarchyWithInstances
when (dump FD.Class) $
do {putStrLn " ---- class hierarchy ---- ";
printClassHierarchy smallClassHierarchy}
-- lift the instance methods up to top-level decls
let cDefBinds = concat [ [ z | z <- ds] | HsClassDecl _ _ ds <- ds]
let myClassAssumps = concat [ classAssumps as | as <- classRecords cHierarchyWithInstances, isClassRecord as ]
instanceEnv = Map.fromList instAssumps
classDefs = snub (concatMap getDeclNames cDefBinds)
classEnv = Map.fromList $ [ (x,y) | (x,y) <- myClassAssumps, x `elem` classDefs ]
(liftedInstances,instAssumps) = mconcatMap (instanceToTopDecls kindInfo cHierarchyWithInstances) ds -- rInstDecls
when (not (null liftedInstances) && (dump FD.Instance) ) $ do
putStrLn " ---- lifted instance declarations ---- "
putStr $ unlines $ map (HsPretty.render . HsPretty.ppHsDecl) liftedInstances
putStrLn $ render $ pprintEnvMap instanceEnv
let funPatBinds = [ d | d <- ds, or' [isHsFunBind, isHsPatBind, isHsForeignDecl, isHsActionDecl] d]
let rTySigs = [ d | d <- ds, or' [isHsTypeSig] d]
-- build an environment of assumptions for all the type signatures
let allTypeSigs = collectSigs (funPatBinds ++ liftedInstances) ++ rTySigs
when (dump FD.Srcsigs) $
do {putStrLn " ---- type signatures from source code (after renaming) ---- ";
putStr $ unlines $ map (HsPretty.render . HsPretty.ppHsDecl) allTypeSigs}
let sigEnv = Map.unions [listSigsToSigEnv kindInfo allTypeSigs,instanceEnv, classEnv]
when (dump FD.Sigenv) $
do {putStrLn " ---- initial sigEnv information ---- ";
putStrLn $ render $ pprintEnvMap sigEnv}
let bindings = (funPatBinds ++ liftedInstances)
--classDefaults = snub [ getDeclName z | z <- cDefBinds, isHsFunBind z || isHsPatBind z ]
classNoDefaults = snub (concat [ getDeclNames z | z <- cDefBinds ]) -- List.\\ classDefaults
noDefaultSigs = Map.fromList [ (n,maybe (error $ "sigEnv:" ++ show n) id $ Map.lookup n sigEnv) | n <- classNoDefaults ]
--when verbose2 $ putStrLn (show bindings)
let programBgs = getBindGroups bindings (nameName . getDeclName) getDeclDeps
when (dump FD.Bindgroups) $
do {putStrLn " \n ---- toplevel variable binding groups ---- ";
putStrLn " ---- Bindgroup # = [members] [vars depended on] [missing vars] ---- \n";
putStr $ debugDeclBindGroups programBgs}
let program = makeProgram sigEnv programBgs
when (dump FD.Program) $ do
putStrLn " ---- Program ---- "
mapM_ putStrLn $ map (render . PPrint.pprint) $ program
-- type inference/checking for all variables
when (dump FD.AllTypes) $ do
putStrLn " ---- all types ---- "
putStrLn $ render $ pprintEnvMap (sigEnv `mappend` localDConsEnv `mappend` hoAssumps hoB)
wdump FD.Progress $ do
putErrLn $ "Type inference"
let moduleName = modInfoName tms
(tms:_) = ms
let tcInfo = tcInfoEmpty {
tcInfoEnv = hoAssumps hoB `mappend` localDConsEnv, -- (importVarEnv `mappend` globalDConsEnv),
tcInfoSigEnv = sigEnv,
tcInfoModName = show moduleName,
tcInfoKindInfo = kindInfo,
tcInfoClassHierarchy = cHierarchyWithInstances
}
(localVarEnv,checkedRules,coercions,tcDs) <- withOptionsT (modInfoOptions tms) $ runTc tcInfo $ do
(tcDs,out) <- listen (tiProgram program ds)
env <- getCollectedEnv
cc <- getCollectedCoerce
let cc' = Map.union cc $ Map.fromList [ (as,lup v) | (as,v) <- outKnots out ]
lup v = case Map.lookup v cc of
Just (CTAbs xs) -> ctAp (map TVar xs)
_ -> ctId
return (env,checkedRules out,cc',tcDs)
when (dump FD.Decls) $ do
putStrLn " \n ---- typechecked code ---- \n"
mapM_ (putStrLn . HsPretty.render . HsPretty.ppHsDecl) tcDs
when (dump FD.Types) $ do
putStrLn " ---- the types of identifiers ---- "
mapM_ putStrLn [ show n ++ " :: " ++ prettyPrintType s | (n,s) <- Map.toList (if verbose2 then localVarEnv else trimEnv localVarEnv)]
when (dump FD.Types) $ do
putStrLn " ---- the coersions of identifiers ---- "
mapM_ putStrLn [ show n ++ " --> " ++ show s | (n,s) <- Map.toList coercions]
localVarEnv <- return $ localVarEnv `Map.union` noDefaultSigs
let pragmaProps = fromList $ Map.toList $ Map.fromListWith mappend [ (toName Name.Val x,fromList $ readProp w) | HsPragmaProps _ w xs <- ds, x <- xs ]
let allAssumps = localDConsEnv `Map.union` localVarEnv
allExports = Set.fromList (concatMap modInfoExport ms)
externalKindEnv = restrictKindEnv (\ x -> isGlobal x && (getModule x `elem` map (Just . modInfoName) ms)) kindInfo
let hoBld = mempty {
hoAssumps = Map.filterWithKey (\k _ -> k `member` allExports) allAssumps,
hoFixities = restrictFixityMap (`member` allExports) thisFixityMap,
-- TODO - this contains unexported names, we should filter these before writing to disk.
hoKinds = externalKindEnv,
--hoKinds = restrictKindEnv (`member` allExports) kindInfo,
hoClassHierarchy = smallClassHierarchy,
hoTypeSynonyms = restrictTypeSynonyms (`member` allExports) thisTypeSynonyms
}
hoEx = mempty {
hoExports = Map.fromList [ (modInfoName m,modInfoExport m) | m <- ms ],
hoDefs = Map.fromList [ (x,(y,filter (`member` allExports) z)) | (x,y,z) <- concat $ map modInfoDefs ms, x `member` allExports]
}
tiData = TiData {
tiDataDecls = tcDs ++ filter isHsClassDecl ds,
tiDataModules = [ (modInfoName m, modInfoHsModule m) | m <- ms],
tiModuleOptions = [ (modInfoName m, modInfoOptions m) | m <- ms],
tiCheckedRules = checkedRules,
tiCoerce = coercions,
tiProps = pragmaProps,
tiAllAssumptions = allAssumps
}
return (mempty { hoBuild = hoBld, hoExp = hoEx },tiData)