Added support for numeric literals in the type inference algorithm
This commit is contained in:
parent
962c1477b9
commit
e09fb2b9ec
|
@ -491,6 +491,9 @@ testUnify = TestList
|
||||||
,fail [("a", A.Int), ("b", A.List A.Infer)] [("a","b")]
|
,fail [("a", A.Int), ("b", A.List A.Infer)] [("a","b")]
|
||||||
,fail [("a", A.Infer)] []
|
,fail [("a", A.Infer)] []
|
||||||
,fail [("a", A.Infer), ("b", A.Infer)] [("a","b")]
|
,fail [("a", A.Infer), ("b", A.Infer)] [("a","b")]
|
||||||
|
|
||||||
|
-- Numeric things:
|
||||||
|
,pass2 [A.InferNum 3, A.Int32] [A.Int32, A.Int32]
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
pass :: [(String, A.Type)] -> [(String, String)] -> [(String, A.Type)]
|
pass :: [(String, A.Type)] -> [(String, String)] -> [(String, A.Type)]
|
||||||
|
|
|
@ -45,9 +45,11 @@ unifyRainTypes :: Map.Map String A.Type -> [(String, String)] -> Either String
|
||||||
(Map.Map String A.Type)
|
(Map.Map String A.Type)
|
||||||
unifyRainTypes m prs
|
unifyRainTypes m prs
|
||||||
= runST $ do m' <- mapToST m
|
= runST $ do m' <- mapToST m
|
||||||
mapM_ (\(x,y) -> unifyType (lookupStartType x m') (lookupStartType y
|
outs <- mapM (\(x,y) -> unifyType (lookupStartType x m') (lookupStartType y
|
||||||
m')) prs
|
m')) prs
|
||||||
stToMap m'
|
case mapMaybe (either Just (const Nothing)) outs of
|
||||||
|
(err:_) -> return $ Left err
|
||||||
|
[] -> stToMap m'
|
||||||
where
|
where
|
||||||
lookupStartType :: String -> Map.Map String (TypeExp s A.Type) -> TypeExp
|
lookupStartType :: String -> Map.Map String (TypeExp s A.Type) -> TypeExp
|
||||||
s A.Type
|
s A.Type
|
||||||
|
@ -73,6 +75,9 @@ unifyRainTypes m prs
|
||||||
read (MutVar v) = readSTRef v >>= \t -> case t of
|
read (MutVar v) = readSTRef v >>= \t -> case t of
|
||||||
Nothing -> return $ Left $ "Type error in unification, found non-unified type"
|
Nothing -> return $ Left $ "Type error in unification, found non-unified type"
|
||||||
Just t' -> read t'
|
Just t' -> read t'
|
||||||
|
read (NumLit v) = readSTRef v >>= \x -> case x of
|
||||||
|
Left _ -> return $ Left $ "Numeric type without concrete type"
|
||||||
|
Right t -> return $ Right t
|
||||||
read x = return $ Left $ "Type error in unification, found: " ++ show x
|
read x = return $ Left $ "Type error in unification, found: " ++ show x
|
||||||
++ " in: " ++ show m
|
++ " in: " ++ show m
|
||||||
|
|
||||||
|
@ -92,20 +97,24 @@ typeToTypeExp (A.Chan A.DirUnknown _ t) = ttte "channel" t
|
||||||
typeToTypeExp (A.Mobile t) = ttte "MOBILE" t
|
typeToTypeExp (A.Mobile t) = ttte "MOBILE" t
|
||||||
typeToTypeExp (A.Infer) = do r <- newSTRef Nothing
|
typeToTypeExp (A.Infer) = do r <- newSTRef Nothing
|
||||||
return $ MutVar r
|
return $ MutVar r
|
||||||
|
typeToTypeExp (A.InferNum n) = do r <- newSTRef $ Left [n]
|
||||||
|
return $ NumLit r
|
||||||
typeToTypeExp t = return $ OperType (toConstr t) []
|
typeToTypeExp t = return $ OperType (toConstr t) []
|
||||||
|
|
||||||
type Ptr s a = STRef s (Maybe (TypeExp s a))
|
type Ptr s a = STRef s (Maybe (TypeExp s a))
|
||||||
|
|
||||||
-- TODO add a special type for numeric literals
|
|
||||||
data TypeExp s a
|
data TypeExp s a
|
||||||
= MutVar (Ptr s a)
|
= MutVar (Ptr s a)
|
||||||
| GenVar Int
|
| GenVar Int
|
||||||
|
-- Either a list of integers that must fit, or a concrete type
|
||||||
|
| NumLit (STRef s (Either [Integer] A.Type))
|
||||||
| OperType Constr [ TypeExp s a ]
|
| OperType Constr [ TypeExp s a ]
|
||||||
|
|
||||||
-- For debugging:
|
-- For debugging:
|
||||||
instance Show (TypeExp s a) where
|
instance Show (TypeExp s a) where
|
||||||
show (MutVar {}) = "MutVar"
|
show (MutVar {}) = "MutVar"
|
||||||
show (GenVar {}) = "GenVar"
|
show (GenVar {}) = "GenVar"
|
||||||
|
show (NumLit {}) = "NumLit"
|
||||||
show (OperType _ ts) = "OperType " ++ show ts
|
show (OperType _ ts) = "OperType " ++ show ts
|
||||||
|
|
||||||
prune :: TypeExp s a -> ST s (TypeExp s a)
|
prune :: TypeExp s a -> ST s (TypeExp s a)
|
||||||
|
@ -132,9 +141,9 @@ occursInType r t =
|
||||||
return (or bs)
|
return (or bs)
|
||||||
|
|
||||||
unifyType :: TypeExp s a -> TypeExp s a -> ST s (Either String ())
|
unifyType :: TypeExp s a -> TypeExp s a -> ST s (Either String ())
|
||||||
unifyType t1 t2
|
unifyType te1 te2
|
||||||
= do t1' <- prune t1
|
= do t1' <- prune te1
|
||||||
t2' <- prune t2
|
t2' <- prune te2
|
||||||
case (t1',t2') of
|
case (t1',t2') of
|
||||||
(MutVar r1, MutVar r2) ->
|
(MutVar r1, MutVar r2) ->
|
||||||
if r1 == r2
|
if r1 == r2
|
||||||
|
@ -152,6 +161,41 @@ unifyType t1 t2
|
||||||
if n1 == n2
|
if n1 == n2
|
||||||
then unifyArgs ts1 ts2
|
then unifyArgs ts1 ts2
|
||||||
else return $ Left "different constructors"
|
else return $ Left "different constructors"
|
||||||
|
(NumLit vns1, NumLit vns2) ->
|
||||||
|
do nst1 <- readSTRef vns1
|
||||||
|
nst2 <- readSTRef vns2
|
||||||
|
case (nst1, nst2) of
|
||||||
|
(Right t1, Right t2) ->
|
||||||
|
if t1 /= t2
|
||||||
|
then return $ Left "Numeric literals bound to different types"
|
||||||
|
else return $ Right ()
|
||||||
|
(Left ns1, Left ns2) ->
|
||||||
|
do writeSTRef vns1 $ Left (ns1 ++ ns2)
|
||||||
|
writeSTRef vns2 $ Left (ns1 ++ ns2)
|
||||||
|
return $ Right ()
|
||||||
|
(Right {}, Left {}) -> unifyType t2' t1'
|
||||||
|
(Left ns1, Right t2) ->
|
||||||
|
if all (willFit t2) ns1
|
||||||
|
then do writeSTRef vns1 (Right t2)
|
||||||
|
return $ Right ()
|
||||||
|
else return $ Left "Numeric literals will not fit in concrete type"
|
||||||
|
(OperType {}, NumLit {}) -> unifyType t2' t1'
|
||||||
|
(NumLit vns1, OperType n1 ts2) ->
|
||||||
|
do nst1 <- readSTRef vns1
|
||||||
|
case nst1 of
|
||||||
|
Right t ->
|
||||||
|
if null ts2 && t == fromConstr n1
|
||||||
|
then return $ Right ()
|
||||||
|
else return $ Left $ "numeric literal cannot be unified"
|
||||||
|
++ " with two different types"
|
||||||
|
Left ns ->
|
||||||
|
if null ts2
|
||||||
|
then if all (willFit $ fromConstr n1) ns
|
||||||
|
then do writeSTRef vns1 $ Right (fromConstr n1)
|
||||||
|
return $ Right ()
|
||||||
|
else return $ Left "Numeric literals will not fit in concrete type"
|
||||||
|
else return $ Left $ "Numeric literal cannot be unified"
|
||||||
|
++ " with non-numeric type"
|
||||||
(_,_) -> return $ Left "different types"
|
(_,_) -> return $ Left "different types"
|
||||||
where
|
where
|
||||||
unifyArgs (x:xs) (y:ys) = do unifyType x y
|
unifyArgs (x:xs) (y:ys) = do unifyType x y
|
||||||
|
@ -165,3 +209,23 @@ instantiate ts x = case x of
|
||||||
OperType nm xs -> OperType nm (map (instantiate ts) xs)
|
OperType nm xs -> OperType nm (map (instantiate ts) xs)
|
||||||
GenVar n -> ts !! n
|
GenVar n -> ts !! n
|
||||||
|
|
||||||
|
willFit :: A.Type -> Integer -> Bool
|
||||||
|
willFit t n = case bounds t of
|
||||||
|
Just (l,h) -> l <= n && n <= h
|
||||||
|
_ -> False
|
||||||
|
where
|
||||||
|
unsigned, signed :: Int -> Maybe (Integer, Integer)
|
||||||
|
signed n = Just (negate $ 2 ^ (n - 1), (2 ^ (n - 1)) - 1)
|
||||||
|
unsigned n = Just (0, (2 ^ n) - 1)
|
||||||
|
|
||||||
|
bounds :: A.Type -> Maybe (Integer, Integer)
|
||||||
|
bounds A.Int8 = signed 8
|
||||||
|
bounds A.Int16 = signed 16
|
||||||
|
bounds A.Int32 = signed 32
|
||||||
|
bounds A.Int64 = signed 64
|
||||||
|
bounds A.Byte = unsigned 8
|
||||||
|
bounds A.UInt16 = unsigned 16
|
||||||
|
bounds A.UInt32 = unsigned 32
|
||||||
|
bounds A.UInt64 = unsigned 64
|
||||||
|
bounds _ = Nothing
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user