helium-1.8: src/Helium/StaticAnalysis/StaticChecks/KindChecking.ag
-----------------------------------------------------------------------------
-- |The Helium Compiler : Static Analysis
--
-- Maintainer : bastiaan@cs.uu.nl
-- Stability : experimental
-- Portability : unknown
--
-- A kind checker for Helium.
--
-- Note: Kind Inferencing for the Helium language is pretty straightforward: check
-- if each type constructor has the right number of arguments, and whether
-- no types are applied to a type variable.
--
-------------------------------------------------------------------------------
ATTR Declarations MaybeDeclarations Declaration
Expression Expressions MaybeExpression GuardedExpression GuardedExpressions
Statement Statements Qualifier Qualifiers
Alternative Alternatives
Body RightHandSide FunctionBinding FunctionBindings
Constructor Constructors AnnotatedTypes AnnotatedType
[ | kindErrors : {[Error]} | ]
SEM Module
| Module body . kindErrors = []
loc . kindErrors = @body.kindErrors
SEM Expression
| Typed lhs . kindErrors = @newErrors ++ @expression.kindErrors
loc . newErrors = checkType @lhs.typeConstructors (@lhs.namesInScope ++ @lhs.allValueConstructors) @type.self
SEM Declaration
| Type lhs . kindErrors = @newErrors ++ @lhs.kindErrors
loc . newErrors = checkType @lhs.typeConstructors (@lhs.namesInScope ++ @lhs.allValueConstructors) @type.self
| TypeSignature lhs . kindErrors = @newErrors ++ @lhs.kindErrors
loc . newErrors = checkType @lhs.typeConstructors (@lhs.namesInScope ++ @lhs.allValueConstructors) @type.self
SEM AnnotatedType
| AnnotatedType lhs . kindErrors = @newErrors ++ @lhs.kindErrors
loc . newErrors = checkType @lhs.typeConstructors (@lhs.namesInScope ++ @lhs.allValueConstructors) @type.self
{
checkType :: M.Map Name Int -> Names -> Type -> [Error]
checkType theTypeConstructors namesInScope t =
let (f, xs) = walkSpine t
xsErrors = concatMap (checkType theTypeConstructors namesInScope) xs
in
xsErrors
++
case f of
Type_Constructor r c ->
checkKind c theTypeConstructors (length xs) namesInScope
++ [ TupleTooBig r
| let nameAsString = show c
, isTupleConstructor nameAsString
, length nameAsString - 1 > 10
]
Type_Variable _ v ->
if length xs /= 0 then
[ TypeVarApplication v ]
else
[]
_ ->
internalError "StaticAnalysis" "checkType" "unexpected type"
walkSpine :: Type -> (Type, [Type])
walkSpine t =
case t of
Type_Variable _ _ -> (t, [])
Type_Constructor _ _ -> (t, [])
Type_Application _ _ f xs ->
let (t', ys) = walkSpine f
in (t', ys ++ xs)
Type_Parenthesized _ t' -> walkSpine t'
Type_Qualified _ _ t' -> walkSpine t'
_ -> internalError "StaticAnalysis" "walkSpine" "unexpected type"
checkKind :: Name -> M.Map Name Int -> Int -> Names -> [Error]
checkKind tycon@(Name_Special _ _ ('(':commas)) _ useArity _ = -- !!!Name
if expected == useArity then
[]
else
[ ArityMismatch TypeConstructor tycon expected useArity]
where
expected =
case length (takeWhile (== ',') commas) of
0 -> 0 -- ()
n -> n + 1 -- (,) (,,) ...
checkKind tycon theTypeConstructors useArity namesInScope =
case M.lookup tycon theTypeConstructors of
Nothing ->
let hint = [ "Constructor "++show (show tycon)++" cannot be used in a type"
| tycon `elem` namesInScope
]
in [ Undefined TypeConstructor tycon (M.keys theTypeConstructors) hint ]
Just defArity ->
if useArity /= defArity then
[ ArityMismatch TypeConstructor tycon defArity useArity ]
else
[ ]
}