-- | inspect types and classes only
-- | extract kinds of type identifier
getIdKind :: TypeEnv -> Id -> Result ((RawKind, [Kind]), Type)
Nothing -> mkError "unknown type" i
Just (TypeInfo rk l _ _) -> return ((rk, l), TypeName i rk 0)
Just (TypeVarDefn rk vk c) -> assert (c > 0) $
return ((rk, [toKind vk]), TypeName i rk c)
-- | extract kinds of co- or invariant type identifiers
getCoVarKind :: Maybe Bool -> TypeEnv -> Id -> Result ((RawKind, [Kind]), Type)
((rk, l), ty) <- getIdKind te i
(ExtKind ek ContraVar _, Just True) -> Result
[mkDiag Hint "wrong contravariance of" i] $ Just ((ek, []), ty)
(ExtKind ek CoVar _, Just False) -> Result
[mkDiag Hint "wrong covariance of" i] $ Just ((ek, []), ty)
_ -> return ((invertKindVariance False rk,
map (invertKindVariance False) $
keepMinKinds (classMap te) l), ty)
-- | check if there is at least one solution
subKinds :: DiagKind -> ClassMap -> Type -> Kind -> [Kind] -> [Kind]
subKinds dk cm ty sk ks res =
if any ( \ k -> lesserKind cm k sk) ks then return res
("no kind found for '" ++ showPretty ty "'" ++
if null ks then "" else expected sk $ head ks)
$ posOfType ty] $ Just []
-- | infer all minimal kinds
inferKinds :: Maybe Bool -> Type -> TypeEnv -> Result ((RawKind, [Kind]), Type)
inferKinds b ty te@Env{classMap = cm} = let
TypeName i _ _ -> getCoVarKind b te i
((rk, ks), t3) <- inferKinds b t1 te
((_, l), t4) <- case rarg of
inferKinds (fmap not b) t2 te
_ -> inferKinds Nothing t2 te
kks <- mapM (getFunKinds cm) ks
rs <- mapM ( \ fk -> case fk of
subKinds Hint cm t2 ek l [res]
_ -> error "inferKinds: no function kind"
) $ keepMinKinds cm $ concat kks
return ((rr, keepMinKinds cm $ concat rs), TypeAppl t3 t4)
_ -> mkError "unexpected type argument" t2
KindedType kt kind ps -> do
let Result ds _ = anaKindM kind cm
k <- if null ds then return kind else Result ds Nothing
((rk, ks), t) <- inferKinds b kt te
l <- subKinds Hint cm kt k ks [k]
return ((rk, l), KindedType t k ps)
l <- mapM ( \ t -> inferKinds b t te) ts
let res@(Result _ mk) = inferKinds b (convertType ty) te
Just (kp, _) -> return (kp, ProductType (map snd l) ps)
(kp, nt) <- inferKinds b t te
return (kp, LazyType nt ps)
(_, t3) <- inferKinds (fmap not b) t1 te
(_, t4) <- inferKinds b t2 te
let res@(Result _ mk) = inferKinds b (convertType ty) te
Just (kp, _) -> return (kp, FunType t3 a t4 ps)
let Result _ mk = inferKinds b t1 te
(kp, t4) <- inferKinds b t2 te
Just (_, t3) -> ExpandedType t3 t4
in -- trace (showPretty ty " : " ++ showPretty resu "")
-- * converting type terms
-- | change lazy, product and fun types to type constructor name with arguments
getTypeAppl :: Type -> (Type, [Type])
getTypeAppl ty = let (t, args) = getTyAppl ty in
getTyAppl typ = case typ of
TypeName _ _ _ -> (typ, [])
TypeAppl t1 t2 -> let (t, args) = getTyAppl t1 in (t, t2 : args)
ExpandedType _ t -> getTyAppl t
LazyType t ps -> getTyAppl $ liftType t ps
KindedType t _ _ -> getTyAppl t
ProductType ts _ -> let n = length ts in
(TypeName (productId n) (prodKind n) 0, ts)
FunType t1 a t2 _ -> (TypeName (arrowId a) funKind 0, [t2, t1])
_ -> error "getTypeAppl: unresolved type"
-- | construct application left-associative
mkTypeAppl :: Type -> [Type] -> Type
mkTypeAppl = foldl ( \ c a -> TypeAppl c a)
-- | change lazy, product and fun types to uniform applications
convertType :: Type -> Type
convertType ty = let (c, args) = getTypeAppl ty in mkTypeAppl c args
-- | extract the raw kind from a type term
rawKindOfType :: Type -> RawKind
rawKindOfType ty = case ty of
TypeAppl t1 _ -> case rawKindOfType t1 of
_ -> error "rawKindOfType"
_ -> rawKindOfType $ convertType ty
lesserType :: TypeEnv -> Type -> Type -> Bool
lesserType te t1 t2 = case (t1, t2) of
(TypeAppl c1 a1, TypeAppl c2 a2) ->
let b1 = lesserType te c1 c2
in (case (rawKindOfType c1, rawKindOfType c2) of
(FunKind ak1 _ _, FunKind ak2 _ _) ->
(ExtKind _ v1 _, ExtKind _ v2 _) ->
if v1 == v2 then case v1 of
_ -> error "lesserType: no FunKind") && lesserType te a1 a2
(TypeName i1 _ _, TypeName i2 _ _) | i1 == i2 -> True
(TypeName i _ _, _) -> case
Map.lookup i $ localTypeVars te of
Just ti -> any ( \ t -> lesserType te t t2) $ superTypes ti
Just (TypeVarDefn _ vk _) -> case vk of
Downset t -> lesserType te t t2
(TypeAppl _ _, TypeName _ _ _) -> False
_ -> lesserType te (convertType t1) $ convertType t2
-- | replace some type names with types
repl ::
Map.Map Id Type -> Type -> Type
repl m = rename ( \ i k n ->
Nothing -> TypeName i k n)
-- | expand aliases in a type scheme
expand :: TypeMap -> TypeScheme -> TypeScheme
expand = mapTypeOfScheme . expandAlias
-- | expand aliases in a type
expandAlias :: TypeMap -> Type -> Type
let (ps, ts, ta, b) = expandAliases tm t in
if b && length ps == length ts then
(map getTypeVar ps) $ reverse ts)) ta
{- | Collect formal and actual parameters of the first argument of a
expandAliases :: TypeMap -> Type -> ([TypeArg], [Type], Type, Bool)
expandAliases tm t = case t of
Just ti -> case typeDefn ti of
AliasTypeDefn (TypeScheme l ty _) ->
Supertype _ (TypeScheme l ty _) _ ->
let (ps, ts, ta, b) = expandAliases tm t1
(ps, t3 : ts, ta, b) -- reverse later on
else wrap $ TypeAppl t1 t3
wrap $ FunType (expandAlias tm t1) a (expandAlias tm t2) ps
ProductType ts ps -> wrap $ ProductType (map (expandAlias tm) ts) ps
LazyType ty ps -> wrap $ LazyType (expandAlias tm ty) ps
ExpandedType t1 t2 -> wrap $ ExpandedType t1 $ expandAlias tm t2
KindedType ty k ps -> wrap $ KindedType (expandAlias tm ty) k ps
where wrap ty = ([], [], ty, False)
-- | find unexpanded alias identifier
hasAlias :: TypeMap -> Type -> [Diagnosis]
map ( \ i -> mkDiag Error ("unexpanded alias '" ++ showId i "' in") t)
Just ti -> case typeDefn ti of
-- * resolve and analyse types
-- | resolve type and infer minimal kinds
anaTypeM :: (Maybe Kind, Type) -> TypeEnv -> Result ((RawKind, [Kind]), Type)
anaTypeM (mk, parsedType) te =
do resolvedType <- mkTypeConstrAppl parsedType
expandedType = expandAlias tm resolvedType
((rk, ks), checkedType) <- inferKinds (Just True) expandedType te
Nothing -> subKinds Error cm parsedType
(if null ks then rk else head ks)
Just k -> subKinds Error cm parsedType k ks $
filter ( \ j -> lesserKind cm j k) ks
Result (hasAlias tm checkedType) $ Just ()
return ((rk, l), checkedType)
-- | resolve the type and check if it is of the universe class
anaStarTypeM :: Type -> TypeEnv -> Result ((RawKind, [Kind]), Type)
anaStarTypeM t = anaTypeM (Just star, t)
-- * misc functions on types
-- | check if an id occurs in a type
cyclicType :: Id -> Type -> Bool
-- | check for unbound (or too many) type variables
unboundTypevars :: Bool -> [TypeArg] -> Type -> [Diagnosis]
unboundTypevars b args ty =
let fvs = map (fst . snd) (leaves (> 0) ty)
argIds = map getTypeVar args
restVars1 = fvs List.\\ argIds
restVars2 = argIds List.\\ fvs
in (if null restVars1 then []
else [mkDiag Error ("unbound type variable(s)\n "
++ showSepList ("," ++) showId
++ if b || null restVars2 then [] else
[mkDiag Warning ("ignoring unused variable(s)\n "
++ showSepList ("," ++) showId
generalizable :: TypeScheme -> [Diagnosis]
generalizable (TypeScheme args ty _) =
(if null args then [] else unboundTypevars False args ty)
++ checkUniqueTypevars args
-- | check uniqueness of type variables
checkUniqueTypevars :: [TypeArg] -> [Diagnosis]
checkUniqueTypevars = checkUniqueness . map getTypeVar