1-----------------------------------------------------------------------------
3-- Module : PureScript.TypeChecker.Types
4-- Copyright : (c) Phil Freeman 2013
7-- Maintainer : Phil Freeman <paf31@cantab.net>
8-- Stability : experimental
13-----------------------------------------------------------------------------
15module PureScript.TypeChecker.Types (
23import Data.Data (Data(..))
24import Data.Generics (everywhere, everywhereM, everything, mkT, mkM, mkQ, extM, extQ)
26import PureScript.Values
27import PureScript.Types
28import PureScript.Kinds
29import PureScript.Names
30import PureScript.TypeChecker.Monad
31import PureScript.TypeChecker.Kinds
32import PureScript.TypeChecker.Synonyms
34import Control.Monad.State
35import Control.Monad.Error
37import Control.Applicative
38import Control.Arrow (Kleisli(..), (***), (&&&))
39import qualified Control.Category as C
41import qualified Data.Map as M
44 = TypeConstraint Int Type
45 | RowConstraint Int Row deriving Show
47newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }
49emptyTypeSolution :: TypeSolution
50emptyTypeSolution = TypeSolution (TUnknown, RUnknown)
52typeOf :: Ident -> Value -> Check PolyType
54 (cs, n) <- case val of
57 (cs, n) <- typeConstraints (M.singleton name me) val
58 return (TypeConstraint me (TUnknown n) : cs, n)
59 _ -> typeConstraints M.empty val
60 solution <- solveTypeConstraints cs emptyTypeSolution
61 let ty = fst (runTypeSolution solution) n
62 allUnknownsBecameQuantified cs solution ty
63 return $ varIfUnknown ty
65allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
66allUnknownsBecameQuantified cs solution ty = do
68 typesMentioned = findUnknownTypes ty
69 unknownTypes = nub $ flip concatMap cs $ \c -> case c of
70 TypeConstraint u t -> u : findUnknownTypes t
71 RowConstraint _ r -> findUnknownTypes r
72 unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes
73 guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned
75 rowsMentioned = findUnknownRows ty
76 unknownRows = nub $ flip concatMap cs $ \c -> case c of
77 TypeConstraint _ t -> findUnknownRows t
78 RowConstraint u r -> u : findUnknownRows r
79 unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
80 guardWith ("Unsolved row variable" ++ show (unsolvedRows \\ rowsMentioned) ++ ", " ++ show cs) $ null $ unsolvedRows \\ rowsMentioned
82findUnknownTypes :: (Data d) => d -> [Int]
83findUnknownTypes = everything (++) (mkQ [] f)
89findTypeVars :: (Data d) => d -> [String]
90findTypeVars = everything (++) (mkQ [] f)
96findUnknownRows :: (Data d) => d -> [Int]
97findUnknownRows = everything (++) (mkQ [] f)
103varIfUnknown :: Type -> PolyType
106 (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty
108 PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'
110 f :: Type -> State (M.Map Int String) Type
115 let name = "t" ++ show (M.size m)
116 put $ M.insert n name m
117 return $ TypeVar name
118 Just name -> return $ TypeVar name
120 g :: Row -> State (M.Map Int String) Row
125 let name = "r" ++ show (M.size m)
126 put $ M.insert n name m
128 Just name -> return $ RowVar name
131replaceVarsWithUnknowns :: [String] -> Type -> Check Type
132replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)
134 f :: Type -> StateT (M.Map String Int) Check Type
135 f (TypeVar var) | var `elem` idents = do
138 case M.lookup var m of
140 put (M.insert var n m)
142 Just u -> return $ TUnknown u
144 g :: Row -> StateT (M.Map String Int) Check Row
145 g (RowVar var) | var `elem` idents = do
148 case M.lookup var m of
150 put (M.insert var n m)
152 Just u -> return $ RUnknown u
155replaceType :: (Data d) => Int -> Type -> d -> d
156replaceType n t = everywhere (mkT go)
158 go (TUnknown m) | m == n = t
161replaceRow :: (Data d) => Int -> Row -> d -> d
162replaceRow n r = everywhere (mkT go)
164 go (RUnknown m) | m == n = r
167typeOccursCheck :: Int -> Type -> Check ()
168typeOccursCheck u (TUnknown _) = return ()
169typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ show t
171rowOccursCheck :: Int -> Row -> Check ()
172rowOccursCheck u (RUnknown _) = return ()
173rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ show r
175occursCheck :: (Data d) => Int -> d -> Bool
176occursCheck u = everything (||) $ flip extQ g $ mkQ False f
178 f (TUnknown u') | u' == u = True
180 g (RUnknown u') | u' == u = True
183typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
184typeConstraints _ (NumericLiteral _) = do
186 return ([TypeConstraint me Number], me)
187typeConstraints _ (StringLiteral _) = do
189 return ([TypeConstraint me String], me)
190typeConstraints _ (BooleanLiteral _) = do
192 return ([TypeConstraint me Boolean], me)
193typeConstraints m (ArrayLiteral vals) = do
194 all <- mapM (typeConstraints m) vals
195 let (cs, ns) = (concat . map fst &&& map snd) all
197 return (cs ++ map (TypeConstraint me . Array . TUnknown) ns, me)
198typeConstraints m (Unary op val) = do
199 (cs, n1) <- typeConstraints m val
201 return (cs ++ unaryOperatorConstraints op n1 me, me)
202typeConstraints m (Binary op left right) = do
203 (cs1, n1) <- typeConstraints m left
204 (cs2, n2) <- typeConstraints m right
206 return (cs1 ++ cs2 ++ binaryOperatorConstraints op n1 n2 me, me)
207typeConstraints m (ObjectLiteral ps) = do
208 all <- mapM (typeConstraints m . snd) ps
209 let (cs, ns) = (concat . map fst &&& map snd) all
211 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
212 return ((TypeConstraint me (Object (typesToRow tys))) : cs, me)
214 typesToRow [] = REmpty
215 typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
216typeConstraints m (Indexer index val) = do
217 (cs1, n1) <- typeConstraints m index
218 (cs2, n2) <- typeConstraints m val
220 return ((TypeConstraint n1 Number) : (TypeConstraint n2 (Array (TUnknown me))) : cs1 ++ cs2, me)
221typeConstraints m (Accessor prop val) = do
222 (cs, n1) <- typeConstraints m val
225 return ((TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest)))) : cs, me)
226typeConstraints m (Abs args ret) = do
227 ns <- replicateM (length args) fresh
228 let m' = m `M.union` M.fromList (zipWith (,) args ns)
229 (cs, n') <- typeConstraints m' ret
231 return ((TypeConstraint me (Function (map TUnknown ns) (TUnknown n'))) : cs, me)
232typeConstraints m (App f xs) = do
233 (cs1, n1) <- typeConstraints m f
234 all <- mapM (typeConstraints m) xs
235 let (cs2, ns) = (concat . map fst &&& map snd) all
237 return ((TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me))) : cs1 ++ cs2, me)
238typeConstraints m (Var var) =
239 case M.lookup var m of
242 case M.lookup var (names env) of
243 Nothing -> throwError $ show var ++ " is undefined"
244 Just (PolyType idents ty, _) -> do
246 replaced <- replaceVarsWithUnknowns idents ty
247 return ([TypeConstraint me replaced], me)
250 return ([TypeConstraint u (TUnknown me)], me)
251typeConstraints m (Block ss) = do
253 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
254 guardWith "Block is missing a return statement" allCodePathsReturn
256typeConstraints m (Constructor c) = do
258 case M.lookup c (dataConstructors env) of
259 Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"
260 Just (PolyType idents ty) -> do
262 replaced <- replaceVarsWithUnknowns idents ty
263 return ([TypeConstraint me replaced], me)
264typeConstraints m (Case val binders) = do
265 (cs1, n1) <- typeConstraints m val
267 cs2 <- typeConstraintsForBinders m n1 ret binders
268 return (cs1 ++ cs2, ret)
269typeConstraints m (TypedValue val poly@(PolyType idents ty)) = do
271 guardWith ("Expected type of kind *, was " ++ show kind) $ kind == Star
272 desugared <- replaceAllTypeSynonyms ty
273 (cs, n1) <- typeConstraints m val
274 return (TypeConstraint n1 desugared : cs, n1)
276replaceAllTypeSynonyms :: Type -> Check Type
277replaceAllTypeSynonyms ty = do
279 go (M.toList $ typeSynonyms env) ty
282 go ((name, (args, repl)):rest) ty = do
283 ty' <- either throwError return (substituteTypeSynonym name args repl ty)
286unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
287unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
288unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
289unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
291binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
292binaryOperatorConstraints Add = symBinOpConstraints Number
293binaryOperatorConstraints Subtract = symBinOpConstraints Number
294binaryOperatorConstraints Multiply = symBinOpConstraints Number
295binaryOperatorConstraints Divide = symBinOpConstraints Number
296binaryOperatorConstraints Modulus = symBinOpConstraints Number
297binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
298binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
299binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
300binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
301binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
302binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
303binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
304binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
305binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
306binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
307binaryOperatorConstraints EqualTo = equalityBinOpConstraints
308binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
309binaryOperatorConstraints And = symBinOpConstraints Boolean
310binaryOperatorConstraints Or = symBinOpConstraints Boolean
311binaryOperatorConstraints Concat = symBinOpConstraints String
313equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
314equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
316symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
317symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
319asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
320asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
322typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
323typeConstraintsForBinder _ NullBinder = return ([], M.empty)
324typeConstraintsForBinder val (StringBinder _) = constantBinder val String
325typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
326typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
327typeConstraintsForBinder val (VarBinder name) = do
329 return ([TypeConstraint me (TUnknown val)], M.singleton name me)
330typeConstraintsForBinder val (NullaryBinder ctor) = do
332 case M.lookup ctor (dataConstructors env) of
333 Just (PolyType args ret) -> do
334 ret' <- replaceVarsWithUnknowns args ret
335 return ([TypeConstraint val ret'], M.empty)
336 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
337typeConstraintsForBinder val (UnaryBinder ctor binder) = do
339 case M.lookup ctor (dataConstructors env) of
340 Just (PolyType idents f@(Function [_] _)) -> do
342 (Function [ty] ret) <- replaceVarsWithUnknowns idents f
343 (cs, m1) <- typeConstraintsForBinder obj binder
344 return ((TypeConstraint val ret) : (TypeConstraint obj ty) : cs, m1)
345 Just _ -> throwError $ ctor ++ " is not a unary constructor"
346 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
347typeConstraintsForBinder val (ObjectBinder props) = do
350 (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
351 return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
353 typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
354 typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
355 typeConstraintsForProperties nrow row ((name, binder):binders) = do
357 (cs1, m1) <- typeConstraintsForBinder propTy binder
358 (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
359 return (cs1 ++ cs2, M.union m1 m2)
360typeConstraintsForBinder val (ArrayBinder binders rest) = do
362 all <- mapM (typeConstraintsForBinder el) binders
363 let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
364 let arrayConstraint = TypeConstraint val (Array (TUnknown el))
366 Nothing -> return (arrayConstraint : cs1, m1)
368 (cs2, m2) <- typeConstraintsForBinder val binder
369 return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
370typeConstraintsForBinder val (NamedBinder name binder) = do
372 (cs, m) <- typeConstraintsForBinder val binder
373 return (TypeConstraint me (TUnknown val) : cs, M.insert name me m)
374typeConstraintsForBinder val (GuardedBinder cond binder) = do
375 (cs1, m) <- typeConstraintsForBinder val binder
376 (cs2, n) <- typeConstraints m cond
377 return (TypeConstraint n Boolean : cs1 ++ cs2, m)
379constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
380constantBinder val ty = return ([TypeConstraint val ty], M.empty)
382typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
383typeConstraintsForBinders _ _ _ [] = return []
384typeConstraintsForBinders m nval ret ((binder, val):bs) = do
385 (cs1, m1) <- typeConstraintsForBinder nval binder
386 (cs2, n2) <- typeConstraints (M.union m m1) val
387 cs3 <- typeConstraintsForBinders m nval ret bs
388 return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
390assignVariable :: Ident -> M.Map Ident Int -> Check ()
391assignVariable name m =
392 case M.lookup name m of
394 Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
396typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
397typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
398 assignVariable name (m `M.union` mass)
399 (cs1, n1) <- typeConstraints m val
400 return $ (cs1, False, M.insert name n1 mass)
401typeConstraintsForStatement m mass ret (Assignment tgt val) = do
402 (cs1, n1) <- typeConstraints m val
403 cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
404 return (cs1 ++ cs2, False, mass)
405typeConstraintsForStatement m mass ret (While val inner) = do
406 (cs1, n1) <- typeConstraints m val
407 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
408 return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
409typeConstraintsForStatement m mass ret (If ifst) = do
410 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
411 return $ (cs, allCodePathsReturn, mass)
412typeConstraintsForStatement m mass ret (For ident start end inner) = do
413 assignVariable ident (m `M.union` mass)
414 (cs1, n1) <- typeConstraints (m `M.union` mass) start
415 (cs2, n2) <- typeConstraints (m `M.union` mass) end
416 let mass1 = M.insert ident n1 mass
417 (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
418 return $ ((TypeConstraint n1 Number) : (TypeConstraint n2 Number) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
419typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
420 assignVariable ident (m `M.union` mass)
422 (cs1, n1) <- typeConstraints (m `M.union` mass) vals
423 let mass1 = M.insert ident val mass
424 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
425 guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
426 return $ ((TypeConstraint n1 (Array (TUnknown val))) : cs1 ++ cs2, False, mass)
427typeConstraintsForStatement m mass ret (Return val) = do
428 (cs1, n1) <- typeConstraints (m `M.union` mass) val
429 return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
431typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
432typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
433 (cs1, n1) <- typeConstraints m val
434 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
435 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn)
436typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
437 (cs1, n1) <- typeConstraints m val
438 (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
439 (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
440 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
442typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
443typeConstraintsForElseStatement m mass ret (Else elses) = do
444 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
445 return (cs, allCodePathsReturn)
446typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
447 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
448 return (cs, allCodePathsReturn)
450typeConstraintsForAssignmentTarget :: M.Map Ident Int -> M.Map Ident Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
451typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
452 case M.lookup var mass of
453 Nothing -> throwError $ "No local variable with name " ++ show var
455 return [TypeConstraint nval (TUnknown ty)]
456typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
458 (cs1, n1) <- typeConstraints (m `M.union` mass) index
459 cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
460 return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
461typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
464 cs <- typeConstraintsForAssignmentTarget m mass obj tgt
465 return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
467typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
468typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
469typeConstraintsForBlock m mass ret (s:ss) = do
470 (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
472 (True, []) -> return (cs1, True, mass1)
473 (True, _) -> throwError "Unreachable code"
475 (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
476 return (cs1 ++ cs2, b2, mass2)
478solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
479solveTypeConstraints [] s = return s
480solveTypeConstraints all@(TypeConstraint n t:cs) s = do
482 let s' = let (f, g) = runTypeSolution s
483 in TypeSolution (replaceType n t . f, replaceType n t . g)
484 cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
485 solveTypeConstraints cs' s'
486solveTypeConstraints (RowConstraint n r:cs) s = do
488 let s' = let (f, g) = runTypeSolution s
489 in TypeSolution $ (replaceRow n r . f, replaceRow n r . g)
490 cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
491 solveTypeConstraints cs' s'
493substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
494substituteTypeInConstraint n s (TypeConstraint m t)
495 | n == m = unifyTypes s t
496 | otherwise = return [TypeConstraint m (replaceType n s t)]
497substituteTypeInConstraint n s (RowConstraint m r)
498 = return [RowConstraint m (replaceType n s r)]
500substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
501substituteRowInConstraint n r (TypeConstraint m t)
502 = return [TypeConstraint m (replaceRow n r t)]
503substituteRowInConstraint n r (RowConstraint m r1)
504 | m == n = unifyRows r r1
505 | otherwise = return [RowConstraint m (replaceRow n r r1)]
507unifyTypes :: Type -> Type -> Check [TypeConstraint]
508unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
509unifyTypes (TUnknown u) t = do
511 return [TypeConstraint u t]
512unifyTypes t (TUnknown u) = do
514 return [TypeConstraint u t]
515unifyTypes Number Number = return []
516unifyTypes String String = return []
517unifyTypes Boolean Boolean = return []
518unifyTypes (Array s) (Array t) = unifyTypes s t
519unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
520unifyTypes (Function args1 ret1) (Function args2 ret2) = do
521 guardWith "Function applied to incorrect number of args" $ length args1 == length args2
522 cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
523 cs2 <- unifyTypes ret1 ret2
525unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
526unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
527unifyTypes (TypeVar v1) (TypeVar v2) = return []
528unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
529 cs1 <- unifyTypes t1 t3
530 cs2 <- unifyTypes t2 t4
532unifyTypes t1 t2 = throwError $ "Cannot unify " ++ show t1 ++ " with " ++ show t2 ++ "."
534unifyRows :: Row -> Row -> Check [TypeConstraint]
537 (s1, r1') = toList r1
538 (s2, r2') = toList r2
539 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
540 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
541 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
542 in rethrow (\e -> "Cannot unify " ++ show r1 ++ " with " ++ show r2 ++ ": " ++ e) $ do
543 cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
544 cs2 <- unifyRows' sd1 r1' sd2 r2'
547 unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
548 unifyRows' [] (RUnknown u) sd r = do
550 return [RowConstraint u (fromList (sd, r))]
551 unifyRows' sd r [] (RUnknown u) = do
553 return [RowConstraint u (fromList (sd, r))]
554 unifyRows' ((name, ty):row) r others (RUnknown u) = do
556 cs <- unifyRows' row r others (RUnknown u')
557 return (RowConstraint u (RCons name ty (RUnknown u')) : cs)
558 unifyRows' [] REmpty [] REmpty = return []
559 unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ show (fromList (sd1, r1)) ++ " with " ++ show (fromList (sd2, r2)) ++ "."
560 toList :: Row -> ([(String, Type)], Row)
561 toList (RCons name ty row) = let (tys, rest) = toList row
562 in ((name, ty):tys, rest)
564 fromList :: ([(String, Type)], Row) -> Row
566 fromList ((name, t):ts, r) = RCons name t (fromList (ts, r))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list