Added Meta tags all over the place in the type unification to give better error messages
This commit is contained in:
parent
6afea19ee6
commit
4429dfc051
|
@ -44,44 +44,45 @@ lookupMapElseMutVar k
|
||||||
case Map.lookup k m of
|
case Map.lookup k m of
|
||||||
Just v -> return v
|
Just v -> return v
|
||||||
Nothing -> do r <- liftIO $ newIORef Nothing
|
Nothing -> do r <- liftIO $ newIORef Nothing
|
||||||
let v = MutVar r
|
let UnifyIndex (mt,_) = k
|
||||||
|
v = MutVar mt r
|
||||||
m' = Map.insert k v m
|
m' = Map.insert k v m
|
||||||
put st {csUnifyLookup = m'}
|
put st {csUnifyLookup = m'}
|
||||||
return v
|
return v
|
||||||
|
|
||||||
ttte :: String -> (A.Type -> A.Type) -> A.Type -> PassM (TypeExp A.Type)
|
ttte :: Meta -> String -> (A.Type -> A.Type) -> A.Type -> PassM (TypeExp A.Type)
|
||||||
ttte c f t = typeToTypeExp t >>= \t' -> return $ OperType c (\[x] -> f x) [t']
|
ttte m c f t = typeToTypeExp m t >>= \t' -> return $ OperType m c (\[x] -> f x) [t']
|
||||||
|
|
||||||
-- Transforms the given type into a typeexp, such that the only inner types
|
-- Transforms the given type into a typeexp, such that the only inner types
|
||||||
-- left will be the primitive types (integer types, float types, bool, time). Arrays
|
-- left will be the primitive types (integer types, float types, bool, time). Arrays
|
||||||
-- (which would require unification of dimensions and such) are not supported,
|
-- (which would require unification of dimensions and such) are not supported,
|
||||||
-- neither are records.
|
-- neither are records.
|
||||||
-- User data types should not be present in the input.
|
-- User data types should not be present in the input.
|
||||||
typeToTypeExp :: A.Type -> PassM (TypeExp A.Type)
|
typeToTypeExp :: Meta -> A.Type -> PassM (TypeExp A.Type)
|
||||||
typeToTypeExp (A.List t) = ttte "[]" A.List t
|
typeToTypeExp m (A.List t) = ttte m "[]" A.List t
|
||||||
typeToTypeExp (A.Chan A.DirInput at t) = ttte "?" (A.Chan A.DirInput at) t
|
typeToTypeExp m (A.Chan A.DirInput at t) = ttte m "?" (A.Chan A.DirInput at) t
|
||||||
typeToTypeExp (A.Chan A.DirOutput at t) = ttte "!" (A.Chan A.DirOutput at) t
|
typeToTypeExp m (A.Chan A.DirOutput at t) = ttte m "!" (A.Chan A.DirOutput at) t
|
||||||
typeToTypeExp (A.Chan A.DirUnknown at t) = ttte "channel" (A.Chan A.DirUnknown at) t
|
typeToTypeExp m (A.Chan A.DirUnknown at t) = ttte m "channel" (A.Chan A.DirUnknown at) t
|
||||||
typeToTypeExp (A.Mobile t) = ttte "MOBILE" A.Mobile t
|
typeToTypeExp m (A.Mobile t) = ttte m "MOBILE" A.Mobile t
|
||||||
typeToTypeExp (A.UnknownVarType en)
|
typeToTypeExp _ (A.UnknownVarType en)
|
||||||
= case en of
|
= case en of
|
||||||
Left n -> lookupMapElseMutVar (UnifyIndex (A.nameMeta n, Right n))
|
Left n -> lookupMapElseMutVar (UnifyIndex (A.nameMeta n, Right n))
|
||||||
Right (m, i) -> lookupMapElseMutVar (UnifyIndex (m, Left i))
|
Right (m, i) -> lookupMapElseMutVar (UnifyIndex (m, Left i))
|
||||||
typeToTypeExp (A.UnknownNumLitType m id n)
|
typeToTypeExp _ (A.UnknownNumLitType m id n)
|
||||||
= do r <- liftIO . newIORef $ Left [n]
|
= do r <- liftIO . newIORef $ Left [(m,n)]
|
||||||
let v = NumLit r
|
let v = NumLit m r
|
||||||
st <- get
|
st <- get
|
||||||
let mp = csUnifyLookup st
|
let mp = csUnifyLookup st
|
||||||
put st {csUnifyLookup = Map.insert (UnifyIndex (m,Left id)) v mp}
|
put st {csUnifyLookup = Map.insert (UnifyIndex (m,Left id)) v mp}
|
||||||
return v
|
return v
|
||||||
typeToTypeExp t = return $ OperType (show t) (const t) []
|
typeToTypeExp m t = return $ OperType m (show t) (const t) []
|
||||||
|
|
||||||
markUnify :: (Typed a, Typed b) => a -> b -> PassM ()
|
markUnify :: (Typed a, Typed b, Data a, Data b) => a -> b -> PassM ()
|
||||||
markUnify x y
|
markUnify x y
|
||||||
= do tx <- astTypeOf x
|
= do tx <- astTypeOf x
|
||||||
ty <- astTypeOf y
|
ty <- astTypeOf y
|
||||||
tex <- typeToTypeExp tx
|
tex <- typeToTypeExp (findMeta x) tx
|
||||||
tey <- typeToTypeExp ty
|
tey <- typeToTypeExp (findMeta y) ty
|
||||||
modify $ \st -> st {csUnifyPairs = (tex,tey) : csUnifyPairs st}
|
modify $ \st -> st {csUnifyPairs = (tex,tey) : csUnifyPairs st}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,11 +102,10 @@ performTypeUnification x
|
||||||
$ x
|
$ x
|
||||||
-- Then, we do the unification:
|
-- Then, we do the unification:
|
||||||
prs <- get >>* csUnifyPairs
|
prs <- get >>* csUnifyPairs
|
||||||
res <- liftIO $ mapM (uncurry unifyType) prs
|
mapM_ (uncurry unifyType) prs
|
||||||
mapM (diePC emptyMeta) (fst $ splitEither res)
|
|
||||||
-- Now put the types back in a map, and replace them through the tree:
|
-- Now put the types back in a map, and replace them through the tree:
|
||||||
l <- get >>* csUnifyLookup
|
l <- get >>* csUnifyLookup
|
||||||
ts <- mapMapWithKeyM (\(UnifyIndex(m,_)) v -> fromTypeExp m v) l
|
ts <- mapMapM (\v -> fromTypeExp v) l
|
||||||
get >>= substituteUnknownTypes ts >>= put
|
get >>= substituteUnknownTypes ts >>= put
|
||||||
substituteUnknownTypes ts x'
|
substituteUnknownTypes ts x'
|
||||||
where
|
where
|
||||||
|
@ -116,7 +116,7 @@ performTypeUnification x
|
||||||
shift' (rawName, d) = do mt <- typeOfSpec (A.ndType d)
|
shift' (rawName, d) = do mt <- typeOfSpec (A.ndType d)
|
||||||
case mt of
|
case mt of
|
||||||
Nothing -> return Nothing
|
Nothing -> return Nothing
|
||||||
Just t -> do te <- typeToTypeExp t
|
Just t -> do te <- typeToTypeExp (A.ndMeta d) t
|
||||||
return $ Just (UnifyIndex (A.ndMeta d, Right name), te)
|
return $ Just (UnifyIndex (A.ndMeta d, Right name), te)
|
||||||
where
|
where
|
||||||
name = A.Name {A.nameName = rawName, A.nameMeta = A.ndMeta d, A.nameType
|
name = A.Name {A.nameName = rawName, A.nameMeta = A.ndMeta d, A.nameType
|
||||||
|
|
|
@ -45,13 +45,11 @@ foldCon con es = case splitEither es of
|
||||||
-- Pearl (2001)", citeseer: http://citeseer.ist.psu.edu/451401.html
|
-- Pearl (2001)", citeseer: http://citeseer.ist.psu.edu/451401.html
|
||||||
-- This in turn was taken from Luca Cardelli's "Basic Polymorphic Type Checking"
|
-- This in turn was taken from Luca Cardelli's "Basic Polymorphic Type Checking"
|
||||||
|
|
||||||
unifyRainTypes :: forall k. (Ord k, Show k) => (Map.Map k (TypeExp A.Type)) -> [(k, k)] -> IO
|
unifyRainTypes :: forall k. (Ord k, Show k) => (Map.Map k (TypeExp A.Type)) -> [(k, k)] ->
|
||||||
(Either (PassM String) (Map.Map k A.Type))
|
PassM (Map.Map k A.Type)
|
||||||
unifyRainTypes m' prs
|
unifyRainTypes m' prs
|
||||||
= do outs <- mapM (\(x,y) -> unifyType (lookupStartType x m') (lookupStartType y m')) prs
|
= do mapM_ (\(x,y) -> unifyType (lookupStartType x m') (lookupStartType y m')) prs
|
||||||
case mapMaybe (either Just (const Nothing)) outs of
|
stToMap m'
|
||||||
(err:_) -> return $ Left err
|
|
||||||
[] -> stToMap m'
|
|
||||||
where
|
where
|
||||||
lookupStartType :: k -> Map.Map k (TypeExp A.Type) -> TypeExp A.Type
|
lookupStartType :: k -> Map.Map k (TypeExp A.Type) -> TypeExp A.Type
|
||||||
lookupStartType s m = case Map.lookup s m of
|
lookupStartType s m = case Map.lookup s m of
|
||||||
|
@ -59,53 +57,56 @@ unifyRainTypes m' prs
|
||||||
Nothing -> error $ "Could not find type for variable in map before unification: "
|
Nothing -> error $ "Could not find type for variable in map before unification: "
|
||||||
++ show s
|
++ show s
|
||||||
|
|
||||||
stToMap :: Map.Map k (TypeExp A.Type) -> IO (Either (PassM String) (Map.Map k A.Type))
|
stToMap :: Map.Map k (TypeExp A.Type) -> PassM (Map.Map k A.Type)
|
||||||
stToMap m = do m' <- mapMapWithKeyM (\k v -> prune v >>= read k) m
|
stToMap m = do m' <- liftIO $ mapMapWithKeyM (\k v -> prune v >>= read k) m
|
||||||
let (mapOfErrs, mapOfRes) = Map.mapEitherWithKey (const id) m'
|
let (mapOfErrs, mapOfRes) = Map.mapEitherWithKey (const id) m'
|
||||||
case Map.elems mapOfErrs of
|
case Map.elems mapOfErrs of
|
||||||
(e:_) -> return $ Left $ return e
|
((m,e):_) -> dieP m e
|
||||||
[] -> return $ Right mapOfRes
|
[] -> return mapOfRes
|
||||||
where
|
where
|
||||||
read :: k -> TypeExp A.Type -> IO (Either String A.Type)
|
read :: k -> TypeExp A.Type -> IO (Either (Meta, String) A.Type)
|
||||||
read k (OperType _ con vals) = do vals' <- mapM (read k) vals
|
read k (OperType m _ con vals)
|
||||||
return $ foldCon con vals'
|
= do vals' <- mapM (read k) vals
|
||||||
read k (MutVar v) = readIORef v >>= \t -> case t of
|
case foldCon con (map (either (Left . snd) Right) vals') of
|
||||||
Nothing -> return $ Left $ "Type error in unification, "
|
Left e -> return $ Left (m, e)
|
||||||
++ "ambigious type remains for: " ++ show k
|
Right x -> return $ Right x
|
||||||
|
read k (MutVar m v) = readIORef v >>= \t -> case t of
|
||||||
|
Nothing -> return $ Left (m, "Type error in unification, "
|
||||||
|
++ "ambigious type remains for: " ++ show k)
|
||||||
Just t' -> read k t'
|
Just t' -> read k t'
|
||||||
read k (NumLit v) = readIORef v >>= \x -> case x of
|
read k (NumLit m v) = readIORef v >>= \x -> case x of
|
||||||
Left _ -> return $ Left $ "Type error in unification, "
|
Left _ -> return $ Left (m, "Type error in unification, "
|
||||||
++ "ambigious type remains for numeric literal: " ++ show k
|
++ "ambigious type remains for numeric literal: " ++ show k)
|
||||||
Right t -> return $ Right t
|
Right t -> return $ Right t
|
||||||
|
|
||||||
fromTypeExp :: Meta -> TypeExp A.Type -> PassM A.Type
|
fromTypeExp :: TypeExp A.Type -> PassM A.Type
|
||||||
fromTypeExp m x = fromTypeExp' =<< (liftIO $ prune x)
|
fromTypeExp x = fromTypeExp' =<< (liftIO $ prune x)
|
||||||
where
|
where
|
||||||
fromTypeExp' :: TypeExp A.Type -> PassM A.Type
|
fromTypeExp' :: TypeExp A.Type -> PassM A.Type
|
||||||
fromTypeExp' (MutVar {}) = dieP m "Unresolved type"
|
fromTypeExp' (MutVar m _) = dieP m "Unresolved type"
|
||||||
fromTypeExp' (GenVar {}) = dieP m "Template vars not yet supported"
|
fromTypeExp' (GenVar m _) = dieP m "Template vars not yet supported"
|
||||||
fromTypeExp' (NumLit v) = liftIO (readIORef v) >>= \x -> case x of
|
fromTypeExp' (NumLit m v) = liftIO (readIORef v) >>= \x -> case x of
|
||||||
Left (n:_) -> dieP m $ "Ambigiously typed numeric literal: " ++ show n
|
Left (n:_) -> dieP m $ "Ambigiously typed numeric literal: " ++ show n
|
||||||
Right t -> return t
|
Right t -> return t
|
||||||
fromTypeExp' (OperType _ f ts) = mapM (fromTypeExp m) ts >>* f
|
fromTypeExp' (OperType _ _ f ts) = mapM fromTypeExp ts >>* f
|
||||||
|
|
||||||
-- For debugging:
|
-- For debugging:
|
||||||
showInErr :: TypeExp A.Type -> PassM String
|
showInErr :: TypeExp A.Type -> PassM String
|
||||||
showInErr (MutVar {}) = return "MutVar"
|
showInErr (MutVar {}) = return "MutVar"
|
||||||
showInErr (GenVar {}) = return "GenVar"
|
showInErr (GenVar {}) = return "GenVar"
|
||||||
showInErr (NumLit {}) = return "NumLit"
|
showInErr (NumLit {}) = return "NumLit"
|
||||||
showInErr t@(OperType {}) = showCode =<< fromTypeExp undefined t
|
showInErr t@(OperType {}) = showCode =<< fromTypeExp t
|
||||||
|
|
||||||
giveErr :: String -> TypeExp A.Type -> TypeExp A.Type -> Either (PassM String) a
|
giveErr :: Meta -> String -> TypeExp A.Type -> TypeExp A.Type -> PassM a
|
||||||
giveErr msg tx ty
|
giveErr m msg tx ty
|
||||||
= Left $ do x <- showInErr tx
|
= do x <- showInErr tx
|
||||||
y <- showInErr ty
|
y <- showInErr ty
|
||||||
return $ msg ++ x ++ " and " ++ y
|
dieP m $ msg ++ x ++ " and " ++ y
|
||||||
|
|
||||||
prune :: Typeable a => TypeExp a -> IO (TypeExp a)
|
prune :: Typeable a => TypeExp a -> IO (TypeExp a)
|
||||||
prune t =
|
prune t =
|
||||||
case t of
|
case t of
|
||||||
MutVar r ->
|
MutVar _ r ->
|
||||||
do m <- readIORef r
|
do m <- readIORef r
|
||||||
case m of
|
case m of
|
||||||
Nothing -> return t
|
Nothing -> return t
|
||||||
|
@ -119,80 +120,75 @@ occursInType :: Typeable a => Ptr a -> TypeExp a -> IO Bool
|
||||||
occursInType r t =
|
occursInType r t =
|
||||||
do t' <- prune t
|
do t' <- prune t
|
||||||
case t' of
|
case t' of
|
||||||
MutVar r2 -> return $ r == r2
|
MutVar _ r2 -> return $ r == r2
|
||||||
GenVar n -> return False
|
GenVar _ n -> return False
|
||||||
OperType _ _ ts -> mapM (occursInType r) ts >>* or
|
OperType _ _ _ ts -> mapM (occursInType r) ts >>* or
|
||||||
|
|
||||||
unifyType :: TypeExp A.Type -> TypeExp A.Type -> IO (Either (PassM String) ())
|
unifyType :: TypeExp A.Type -> TypeExp A.Type -> PassM ()
|
||||||
unifyType te1 te2
|
unifyType te1 te2
|
||||||
= do t1' <- prune te1
|
= do t1' <- liftIO $ prune te1
|
||||||
t2' <- prune te2
|
t2' <- liftIO $ prune te2
|
||||||
case (t1',t2') of
|
case (t1',t2') of
|
||||||
(MutVar r1, MutVar r2) ->
|
(MutVar _ r1, MutVar _ r2) ->
|
||||||
if r1 == r2
|
if r1 == r2
|
||||||
then return $ Right ()
|
then return ()
|
||||||
else liftM Right $ writeIORef r1 (Just t2')
|
else liftIO $ writeIORef r1 (Just t2')
|
||||||
(MutVar r1, _) ->
|
(MutVar m r1, _) ->
|
||||||
do b <- occursInType r1 t2'
|
do b <- liftIO $ occursInType r1 t2'
|
||||||
if b
|
if b
|
||||||
then return $ Left $ return "occurs in"
|
then dieP m "Infinitely recursive type formed"
|
||||||
else liftM Right $ writeIORef r1 (Just t2')
|
else liftIO $ writeIORef r1 (Just t2')
|
||||||
(_,MutVar _) -> unifyType t2' t1'
|
(_,MutVar {}) -> unifyType t2' t1'
|
||||||
(GenVar n,GenVar m) ->
|
(GenVar m x,GenVar _ y) ->
|
||||||
if n == m then return $ Right () else return $ Left $ return "different genvars"
|
if x == y then return () else dieP m $ "different template variables"
|
||||||
(OperType n1 _ ts1,OperType n2 _ ts2) ->
|
++ " cannot be assumed to be equal"
|
||||||
|
(OperType m1 n1 _ ts1,OperType m2 n2 _ ts2) ->
|
||||||
if n1 == n2
|
if n1 == n2
|
||||||
then unifyArgs ts1 ts2
|
then unifyArgs ts1 ts2
|
||||||
else return $ giveErr "Different constructors: " t1' t2'
|
else giveErr m1 "Type cannot be matched: " t1' t2'
|
||||||
(NumLit vns1, NumLit vns2) ->
|
(NumLit m1 vns1, NumLit m2 vns2) ->
|
||||||
do nst1 <- readIORef vns1
|
do nst1 <- liftIO $ readIORef vns1
|
||||||
nst2 <- readIORef vns2
|
nst2 <- liftIO $ readIORef vns2
|
||||||
case (nst1, nst2) of
|
case (nst1, nst2) of
|
||||||
(Right t1, Right t2) ->
|
(Right t1, Right t2) ->
|
||||||
if t1 /= t2
|
if t1 /= t2
|
||||||
then return $ Left $ return "Numeric literals bound to different types"
|
then dieP m1 "Numeric literals bound to different types"
|
||||||
else return $ Right ()
|
else return ()
|
||||||
(Left ns1, Left ns2) ->
|
(Left ns1, Left ns2) ->
|
||||||
do writeIORef vns1 $ Left (ns1 ++ ns2)
|
do liftIO $ writeIORef vns1 $ Left (ns1 ++ ns2)
|
||||||
writeIORef vns2 $ Left (ns2 ++ ns1)
|
liftIO $ writeIORef vns2 $ Left (ns2 ++ ns1)
|
||||||
return $ Right ()
|
|
||||||
(Right {}, Left {}) -> unifyType t2' t1'
|
(Right {}, Left {}) -> unifyType t2' t1'
|
||||||
(Left ns1, Right t2) ->
|
(Left ns1, Right t2) ->
|
||||||
if all (willFit t2) ns1
|
if all (willFit t2) (map snd ns1)
|
||||||
then do writeIORef vns1 (Right t2)
|
then liftIO $ writeIORef vns1 (Right t2)
|
||||||
return $ Right ()
|
else dieP m1 "Numeric literals will not fit in concrete type"
|
||||||
else return $ Left $ return "Numeric literals will not fit in concrete type"
|
|
||||||
(OperType {}, NumLit {}) -> unifyType t2' t1'
|
(OperType {}, NumLit {}) -> unifyType t2' t1'
|
||||||
(NumLit vns1, OperType n1 f ts2) ->
|
(NumLit m1 vns1, OperType m2 n2 f ts2) ->
|
||||||
do nst1 <- readIORef vns1
|
do nst1 <- liftIO $ readIORef vns1
|
||||||
case nst1 of
|
case nst1 of
|
||||||
Right t ->
|
Right t ->
|
||||||
if null ts2 && t == f []
|
if null ts2 && t == f []
|
||||||
then return $ Right ()
|
then return ()
|
||||||
else return $ Left $ return $ "numeric literal cannot be unified"
|
else dieP m1 $ "numeric literal cannot be unified"
|
||||||
++ " with two different types"
|
++ " with two different types"
|
||||||
Left ns ->
|
Left ns ->
|
||||||
if null ts2
|
if null ts2
|
||||||
then if all (willFit $ f []) ns
|
then if all (willFit $ f []) (map snd ns)
|
||||||
then do writeIORef vns1 $ Right (f [])
|
then liftIO $ writeIORef vns1 $ Right (f [])
|
||||||
return $ Right ()
|
else dieP m1 "Numeric literals will not fit in concrete type"
|
||||||
else return $ Left $ return "Numeric literals will not fit in concrete type"
|
else dieP m1 $ "Numeric literal cannot be unified"
|
||||||
else return $ Left $ return $ "Numeric literal cannot be unified"
|
|
||||||
++ " with non-numeric type"
|
++ " with non-numeric type"
|
||||||
(_,_) -> return $ Left $ return "different types"
|
(t,_) -> dieP (findMeta t) "different types"
|
||||||
where
|
where
|
||||||
unifyArgs (x:xs) (y:ys) = do r <- unifyType x y
|
unifyArgs (x:xs) (y:ys) = unifyType x y >> unifyArgs xs ys
|
||||||
case r of
|
unifyArgs [] [] = return ()
|
||||||
Left _ -> return r
|
unifyArgs xs ys = dieP (findMeta (xs,ys)) "different lengths"
|
||||||
Right _ -> unifyArgs xs ys
|
|
||||||
unifyArgs [] [] = return $ Right ()
|
|
||||||
unifyArgs _ _ = return $ Left $ return "different lengths"
|
|
||||||
|
|
||||||
instantiate :: Typeable a => [TypeExp a] -> TypeExp a -> TypeExp a
|
instantiate :: Typeable a => [TypeExp a] -> TypeExp a -> TypeExp a
|
||||||
instantiate ts x = case x of
|
instantiate ts x = case x of
|
||||||
MutVar _ -> x
|
MutVar _ _ -> x
|
||||||
OperType nm f xs -> OperType nm f (map (instantiate ts) xs)
|
OperType m nm f xs -> OperType m nm f (map (instantiate ts) xs)
|
||||||
GenVar n -> ts !! n
|
GenVar _ n -> ts !! n
|
||||||
|
|
||||||
willFit :: A.Type -> Integer -> Bool
|
willFit :: A.Type -> Integer -> Bool
|
||||||
willFit t n = case bounds t of
|
willFit t n = case bounds t of
|
||||||
|
|
|
@ -22,13 +22,14 @@ import Data.Generics
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
|
|
||||||
import qualified AST as A
|
import qualified AST as A
|
||||||
|
import Metadata
|
||||||
|
|
||||||
type Ptr a = IORef (Maybe (TypeExp a))
|
type Ptr a = IORef (Maybe (TypeExp a))
|
||||||
|
|
||||||
data Typeable a => TypeExp a
|
data Typeable a => TypeExp a
|
||||||
= MutVar (Ptr a)
|
= MutVar Meta (Ptr a)
|
||||||
| GenVar Int
|
| GenVar Meta Int
|
||||||
-- Either a list of integers that must fit, or a concrete type
|
-- Either a list of integers that must fit, or a concrete type
|
||||||
| NumLit (IORef (Either [Integer] A.Type))
|
| NumLit Meta (IORef (Either [(Meta, Integer)] A.Type))
|
||||||
| OperType String ([A.Type] -> A.Type) [ TypeExp a ]
|
| OperType Meta String ([A.Type] -> A.Type) [ TypeExp a ]
|
||||||
deriving (Typeable, Data)
|
deriving (Typeable, Data)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user