-- | check the kind and compute the raw kind
anaKindM :: Kind -> ClassMap -> Result RawKind
anaKindM k cm = case k of
ClassKind ci -> if k == universe then return rStar
Just (ClassInfo rk _) -> return rk
Nothing -> Result [mkDiag Error "not a class" ci] $ Just rStar
return $ FunKind v rk1 rk2 ps
-- | get minimal function kinds of (class) kind
getFunKinds :: Monad m => ClassMap -> Kind -> m (
Set.Set Kind)
getFunKinds cm k = case k of
ks <- mapM (getFunKinds cm) $
Set.toList $ classKinds info
return $ keepMinKinds cm ks
_ -> fail $ "not a function kind '" ++ showId c "'"
-- | compute arity from a raw kind
kindArity :: RawKind -> Int
FunKind _ _ rk _ -> 1 + kindArity rk
-- | check if a class occurs in one of its super kinds
cyclicClassId :: ClassMap -> Id -> Kind -> Bool
cyclicClassId cm ci k = case k of
FunKind _ k1 k2 _ -> cyclicClassId cm ci k1 || cyclicClassId cm ci k2
ClassKind cj -> cj /= universeId &&
-- | keep only minimal elements according to 'lesserKind'
-- | no kind of the set is lesser than the new kind
newKind :: ClassMap -> Kind ->
Set.Set Kind -> Bool
-- | add a new kind to a set
lesserVariance :: Variance -> Variance -> Bool
lesserVariance v1 v2 = case v1 of
revVariance :: Variance -> Variance
revVariance v = case v of
-- | compute the minimal variance
minVariance :: Variance -> Variance -> Variance
minVariance v1 v2 = case v1 of
_ -> if v1 == v2 then v1 else InVar
-- | check subkinding (kinds with variances are greater)
lesserKind :: ClassMap -> Kind -> Kind -> Bool
lesserKind cm k1 k2 = case k1 of
ClassKind c1 -> (case k2 of
ClassKind c2 -> c1 == c2 || if k1 == universe then
False else k2 == universe
Just info -> not $ newKind cm k2 $ classKinds info
FunKind v1 a1 r1 _ -> case k2 of
FunKind v2 a2 r2 _ -> lesserVariance v1 v2
&& lesserKind cm r1 r2 && lesserKind cm a2 a1
lesserRawKind :: RawKind -> RawKind -> Bool
lesserRawKind k1 k2 = case k1 of
ClassKind _ -> case k2 of
FunKind v1 a1 r1 _ -> case k2 of
FunKind v2 a2 r2 _ -> lesserVariance v1 v2
&& lesserRawKind r1 r2 && lesserRawKind a2 a1
minRawKind :: Monad m => String -> RawKind -> RawKind -> m RawKind
minRawKind str k1 k2 = let err = fail $ diffKindString str k1 k2 in case k1 of
ClassKind _ -> case k2 of
ClassKind _ -> return $ ClassKind ()
FunKind v1 a1 r1 ps -> case k2 of
FunKind v2 a2 r2 qs -> do
a3 <- minRawKind str a2 a1
r3 <- minRawKind str r1 r2
return $ FunKind (minVariance v1 v2) a3 r3 $ appRange ps qs
rawToKind :: RawKind -> Kind
rawToKind = mapKind (const universeId)
-- | create message for different kinds
diffKindString :: String -> RawKind -> RawKind -> String
diffKindString a k1 k2 = "incompatible kind of: " ++ a ++
expected (rawToKind k1) (rawToKind k2)
-- | create diagnostic for different kinds
diffKindDiag :: (GetRange a, Pretty a) =>
a -> RawKind -> RawKind -> [Diagnosis]
[Diag Error (diffKindString (showDoc a "") k1 k2) $ getRange a]
-- | check if raw kinds are compatible
checkKinds :: (GetRange a, Pretty a) =>
a -> RawKind -> RawKind -> [Diagnosis]
maybe (diffKindDiag p k1 k2) (const []) $ minRawKind "" k1 k2
anaClassDecls :: ClassDecl -> State Env ClassDecl
anaClassDecls (ClassDecl cls k ps) =
let Result ds (Just rk) = anaKindM k cm
let ak = if null ds then k else universe
mapM_ (addClassDecl rk ak) cls
return $ ClassDecl cls ak ps
addClassDecl :: RawKind -> Kind -> Id -> State Env ()
addClassDecl rk kind ci =
addDiags [mkDiag Warning "void universe class declaration" ci]
Just _ -> addDiags [mkDiag Error "class name already a type" ci]
[mkDiag Error "class name already a type variable" ci]
addSymbol $ idToClassSymbol e ci rk
Just (ClassInfo ork superClasses) ->
let Result ds mk = minRawKind (showDoc ci "") rk ork
if cyclicClassId cm ci kind then
addDiags [mkDiag Error "cyclic class" ci]
addSymbol $ idToClassSymbol e ci nk
if newKind cm kind superClasses then do
addDiags [mkDiag Hint "refined class" ci]
(ClassInfo nk $ addNewKind cm kind superClasses) cm
else addDiags [mkDiag Warning "unchanged class" ci]