module Imports (importInterfaces, importModules, qualifyEnv) where
import Data.List (nubBy)
import qualified Data.Map as Map
import Data.Maybe (catMaybes, fromMaybe, isJust)
import qualified Data.Set as Set
import Curry.Base.Ident
import Curry.Base.SpanInfo
import Curry.Base.Monad
import Curry.Syntax
import Base.CurryKinds (toKind')
import Base.CurryTypes ( toQualType, toQualTypes, toQualPredType, toConstrType
, toMethodType )
import Base.Kinds
import Base.Messages
import Base.TopEnv
import Base.Types
import Base.TypeSubst
import Env.Class
import Env.Instance
import Env.Interface
import Env.ModuleAlias (importAliases, initAliasEnv)
import Env.OpPrec
import Env.TypeConstructor
import Env.Value
import CompilerEnv
importModules :: Monad m => Module a -> InterfaceEnv -> [ImportDecl]
-> CYT m CompilerEnv
importModules mdl@(Module _ _ mid _ _ _) iEnv expImps
= ok $ foldl importModule initEnv expImps
where
initEnv = (initCompilerEnv mid)
{ aliasEnv = importAliases expImps
, interfaceEnv = iEnv
, extensions = knownExtensions mdl
}
importModule env (ImportDecl _ m q asM is) =
case Map.lookup m iEnv of
Just intf -> importInterface (fromMaybe m asM) q is intf env
Nothing -> internalError $ "Imports.importModules: no interface for "
++ show m
importInterfaces :: Interface -> InterfaceEnv -> CompilerEnv
importInterfaces (Interface m is _) iEnv
= importUnifyData $ foldl importModule initEnv is
where
initEnv = (initCompilerEnv m) { aliasEnv = initAliasEnv, interfaceEnv = iEnv }
importModule env (IImportDecl _ i) = case Map.lookup i iEnv of
Just intf -> importInterfaceIntf intf env
Nothing -> internalError $ "Imports.importInterfaces: no interface for "
++ show m
importInterface :: ModuleIdent -> Bool -> Maybe ImportSpec -> Interface
-> CompilerEnv -> CompilerEnv
importInterface m q is (Interface mid _ ds) env = env'
where
env' = env
{ opPrecEnv = importEntities (precs mid) m q vs id ds $ opPrecEnv env
, tyConsEnv = importEntities (types mid) m q ts (importData vs) ds $ tyConsEnv env
, valueEnv = importEntities (values mid) m q vs id ds $ valueEnv env
, classEnv = importClasses mid ds $ classEnv env
, instEnv = importInstances mid ds $ instEnv env
}
ts = isVisible addType is
vs = isVisible addValue is
addType :: Import -> [Ident] -> [Ident]
addType (Import _ _) tcs = tcs
addType (ImportTypeWith _ tc _) tcs = tc : tcs
addType (ImportTypeAll _ _) _ = internalError "Imports.addType"
addValue :: Import -> [Ident] -> [Ident]
addValue (Import _ f) fs = f : fs
addValue (ImportTypeWith _ _ cs) fs = cs ++ fs
addValue (ImportTypeAll _ _) _ = internalError "Imports.addValue"
isVisible :: (Import -> [Ident] -> [Ident]) -> Maybe ImportSpec
-> Ident -> Bool
isVisible _ Nothing = const True
isVisible add (Just (Importing _ xs)) = (`Set.member` Set.fromList (foldr add [] xs))
isVisible add (Just (Hiding _ xs)) = (`Set.notMember` Set.fromList (foldr add [] xs))
importEntities :: Entity a => (IDecl -> [a]) -> ModuleIdent -> Bool
-> (Ident -> Bool) -> (a -> a) -> [IDecl] -> TopEnv a -> TopEnv a
importEntities ents m q isVisible' f ds env =
foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env
[ (x, f y) | y <- concatMap ents ds
, let x = unqualify (origName y), isVisible' x
]
where importUnqual m' x y = importTopEnv m' x y . qualImportTopEnv m' x y
importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo
importData isVisible' (DataType tc k cs) =
DataType tc k $ catMaybes $ map (importConstr isVisible') cs
importData isVisible' (RenamingType tc k nc) =
maybe (DataType tc k []) (RenamingType tc k) (importConstr isVisible' nc)
importData _ (AliasType tc k n ty) = AliasType tc k n ty
importData isVisible' (TypeClass qcls k ms) =
TypeClass qcls k $ catMaybes $ map (importMethod isVisible') ms
importData _ (TypeVar _) = internalError "Imports.importData: type variable"
importConstr :: (Ident -> Bool) -> DataConstr -> Maybe DataConstr
importConstr isVisible' dc
| isVisible' (constrIdent dc) = Just dc
| otherwise = Nothing
importMethod :: (Ident -> Bool) -> ClassMethod -> Maybe ClassMethod
importMethod isVisible' mthd
| isVisible' (methodName mthd) = Just mthd
| otherwise = Nothing
importClasses :: ModuleIdent -> [IDecl] -> ClassEnv -> ClassEnv
importClasses m = flip $ foldr (bindClass m)
bindClass :: ModuleIdent -> IDecl -> ClassEnv -> ClassEnv
bindClass m (HidingClassDecl p cx cls k tv) =
bindClass m (IClassDecl p cx cls k tv [] [])
bindClass m (IClassDecl _ cx cls _ _ ds ids) =
bindClassInfo (qualQualify m cls) (sclss, ms)
where sclss = map (\(Constraint _ scls _) -> qualQualify m scls) cx
ms = map (\d -> (imethod d, isJust $ imethodArity d)) $ filter isVis ds
isVis (IMethodDecl _ idt _ _ ) = idt `notElem` ids
bindClass _ _ = id
importInstances :: ModuleIdent -> [IDecl] -> InstEnv -> InstEnv
importInstances m = flip $ foldr (bindInstance m)
bindInstance :: ModuleIdent -> IDecl -> InstEnv -> InstEnv
bindInstance m (IInstanceDecl _ cx qcls ty is mm) = bindInstInfo
(qualQualify m qcls, qualifyTC m $ typeConstr ty) (fromMaybe m mm, ps, is)
where PredType ps _ = toQualPredType m [] $ QualTypeExpr NoSpanInfo cx ty
bindInstance _ _ = id
precs :: ModuleIdent -> IDecl -> [PrecInfo]
precs m (IInfixDecl _ fix prec op) = [PrecInfo (qualQualify m op) (OpPrec fix prec)]
precs _ _ = []
hiddenTypes :: ModuleIdent -> IDecl -> [TypeInfo]
hiddenTypes m (HidingDataDecl _ tc k tvs) = [typeCon DataType m tc k tvs []]
hiddenTypes m (HidingClassDecl _ _ qcls k _) = [typeCls m qcls k []]
hiddenTypes m d = types m d
types :: ModuleIdent -> IDecl -> [TypeInfo]
types m (IDataDecl _ tc k tvs cs _) =
[typeCon DataType m tc k tvs (map mkData cs)]
where
mkData (ConstrDecl _ c tys) =
DataConstr c (toQualTypes m tvs tys)
mkData (ConOpDecl _ ty1 c ty2) =
DataConstr c (toQualTypes m tvs [ty1, ty2])
mkData (RecordDecl _ c fs) =
RecordConstr c labels (toQualTypes m tvs tys)
where (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]
types m (INewtypeDecl _ tc k tvs nc _) =
[typeCon RenamingType m tc k tvs (mkData nc)]
where
mkData (NewConstrDecl _ c ty) =
DataConstr c [toQualType m tvs ty]
mkData (NewRecordDecl _ c (l, ty)) =
RecordConstr c [l] [toQualType m tvs ty]
types m (ITypeDecl _ tc k tvs ty) =
[typeCon aliasType m tc k tvs (toQualType m tvs ty)]
where
aliasType tc' k' = AliasType tc' k' (length tvs)
types m (IClassDecl _ _ qcls k tv ds ids) =
[typeCls m qcls k (map mkMethod $ filter isVis ds)]
where
isVis (IMethodDecl _ f _ _ ) = f `notElem` ids
mkMethod (IMethodDecl _ f a qty) = ClassMethod f a $
qualifyPredType m $ normalize 1 $ toMethodType qcls tv qty
types _ _ = []
typeCon :: (QualIdent -> Kind -> a) -> ModuleIdent -> QualIdent
-> Maybe KindExpr -> [Ident] -> a
typeCon f m tc k tvs = f (qualQualify m tc) (toKind' k (length tvs))
typeCls :: ModuleIdent -> QualIdent -> Maybe KindExpr -> [ClassMethod]
-> TypeInfo
typeCls m qcls k ms = TypeClass (qualQualify m qcls) (toKind' k 0) ms
values :: ModuleIdent -> IDecl -> [ValueInfo]
values m (IDataDecl _ tc _ tvs cs hs) =
map (dataConstr m tc' tvs)
(filter ((\con -> con `notElem` hs || isHiddenButNeeded con)
. constrId) cs) ++
map (recLabel m tc' tvs ty') (nubBy sameLabel clabels)
where tc' = qualQualify m tc
ty' = constrType tc' tvs
labels = [ (l, lty) | RecordDecl _ _ fs <- cs
, FieldDecl _ ls lty <- fs, l <- ls, l `notElem` hs
]
clabels = [(l, constr l, ty) | (l, ty) <- labels]
constr l = [constrId c | c <- cs, l `elem` recordLabels c]
hiddenCs = [c | (l, _) <- labels, c <- constr l, c `elem` hs]
isHiddenButNeeded = flip elem hiddenCs
sameLabel (l1,_,_) (l2,_,_) = l1 == l2
values m (INewtypeDecl _ tc _ tvs nc hs) =
map (newConstr m tc' tvs) [nc | nconstrId nc `notElem` hs] ++
case nc of
NewConstrDecl _ _ _ -> []
NewRecordDecl _ c (l, lty) ->
[recLabel m tc' tvs ty' (l, [c], lty) | l `notElem` hs]
where tc' = qualQualify m tc
ty' = constrType tc' tvs
values m (IFunctionDecl _ f Nothing a qty) =
[Value (qualQualify m f) False a (typeScheme (toQualPredType m [] qty))]
values m (IFunctionDecl _ f (Just tv) _ qty) =
[Value (qualQualify m f) True 0 (typeScheme (toQualPredType m [tv] qty))]
values m (IClassDecl _ _ qcls _ tv ds hs) =
map (classMethod m qcls' tv) (filter ((`notElem` hs) . imethod) ds)
where qcls' = qualQualify m qcls
values _ _ = []
dataConstr :: ModuleIdent -> QualIdent -> [Ident] -> ConstrDecl -> ValueInfo
dataConstr m tc tvs (ConstrDecl _ c tys) =
DataConstructor (qualifyLike tc c) a labels $
constrType' m tc tvs tys
where a = length tys
labels = replicate a anonId
dataConstr m tc tvs (ConOpDecl _ ty1 op ty2) =
DataConstructor (qualifyLike tc op) 2 [anonId, anonId] $
constrType' m tc tvs [ty1, ty2]
dataConstr m tc tvs (RecordDecl _ c fs) =
DataConstructor (qualifyLike tc c) a labels $
constrType' m tc tvs tys
where fields = [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]
(labels, tys) = unzip fields
a = length labels
newConstr :: ModuleIdent -> QualIdent -> [Ident] -> NewConstrDecl -> ValueInfo
newConstr m tc tvs (NewConstrDecl _ c ty1) =
NewtypeConstructor (qualifyLike tc c) anonId $
constrType' m tc tvs [ty1]
newConstr m tc tvs (NewRecordDecl _ c (l, ty1)) =
NewtypeConstructor (qualifyLike tc c) l $
constrType' m tc tvs [ty1]
recLabel :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr
-> (Ident, [Ident], TypeExpr) -> ValueInfo
recLabel m tc tvs ty0 (l, cs, lty) = Label ql qcs tySc
where ql = qualifyLike tc l
qcs = map (qualifyLike tc) cs
tySc = polyType (toQualType m tvs (ArrowType NoSpanInfo ty0 lty))
constrType' :: ModuleIdent -> QualIdent -> [Ident] -> [TypeExpr] -> TypeScheme
constrType' m tc tvs tys = ForAll (length tvs) pty
where pty = qualifyPredType m $ toConstrType tc tvs tys
constrType :: QualIdent -> [Ident] -> TypeExpr
constrType tc tvs = foldl (ApplyType NoSpanInfo) (ConstructorType NoSpanInfo tc)
$ map (VariableType NoSpanInfo) tvs
classMethod :: ModuleIdent -> QualIdent -> Ident -> IMethodDecl -> ValueInfo
classMethod m qcls tv (IMethodDecl _ f _ qty) =
Value (qualifyLike qcls f) True 0 $
typeScheme $ qualifyPredType m $ toMethodType qcls tv qty
importUnifyData :: CompilerEnv -> CompilerEnv
importUnifyData cEnv = cEnv { tyConsEnv = importUnifyData' $ tyConsEnv cEnv }
importUnifyData' :: TCEnv -> TCEnv
importUnifyData' tcEnv = fmap (setInfo allTyCons) tcEnv
where
setInfo tcs t = case Map.lookup (origName t) tcs of
Nothing -> error "Imports.importUnifyData'"
Just ty -> ty
allTyCons = foldr (mergeData . snd) Map.empty $ allImports tcEnv
mergeData t tcs =
Map.insert tc (maybe t (sureMerge t) $ Map.lookup tc tcs) tcs
where tc = origName t
sureMerge x y = case merge x y of
Nothing -> error "Imports.importUnifyData'.sureMerge"
Just z -> z
qualifyEnv :: CompilerEnv -> CompilerEnv
qualifyEnv env = qualifyLocal env
$ foldl (flip importInterfaceIntf) initEnv
$ Map.elems
$ interfaceEnv env
where initEnv = initCompilerEnv $ moduleIdent env
qualifyLocal :: CompilerEnv -> CompilerEnv -> CompilerEnv
qualifyLocal currentEnv initEnv = currentEnv
{ opPrecEnv = foldr bindQual pEnv $ localBindings $ opPrecEnv currentEnv
, tyConsEnv = foldr bindQual tcEnv $ localBindings $ tyConsEnv currentEnv
, valueEnv = foldr bindGlobal tyEnv $ localBindings $ valueEnv currentEnv
, classEnv = Map.unionWith mergeClassInfo clsEnv $ classEnv currentEnv
, instEnv = Map.union iEnv $ instEnv currentEnv
}
where
pEnv = opPrecEnv initEnv
tcEnv = tyConsEnv initEnv
tyEnv = valueEnv initEnv
clsEnv = classEnv initEnv
iEnv = instEnv initEnv
bindQual (_, y) = qualBindTopEnv (origName y) y
bindGlobal (x, y)
| hasGlobalScope x = bindQual (x, y)
| otherwise = bindTopEnv x y
importInterfaceIntf :: Interface -> CompilerEnv -> CompilerEnv
importInterfaceIntf (Interface m _ ds) env = env
{ opPrecEnv = importEntitiesIntf m (precs m) ds $ opPrecEnv env
, tyConsEnv = importEntitiesIntf m (hiddenTypes m) ds $ tyConsEnv env
, valueEnv = importEntitiesIntf m (values m) ds $ valueEnv env
, classEnv = importClasses m ds $ classEnv env
, instEnv = importInstances m ds $ instEnv env
}
importEntitiesIntf :: Entity a => ModuleIdent -> (IDecl -> [a]) -> [IDecl]
-> TopEnv a -> TopEnv a
importEntitiesIntf m ents ds env = foldr importEntity env (concatMap ents ds)
where importEntity x = qualImportTopEnv (fromMaybe m (qidModule (origName x)))
(unqualify (origName x)) x