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
55 (cs, n) <- typeConstraints (M.singleton name me) val
56 let allConstraints = TypeConstraint me (TUnknown n) : cs
57 solution <- solveTypeConstraints allConstraints emptyTypeSolution
58 let ty = fst (runTypeSolution solution) n
59 allUnknownsBecameQuantified allConstraints solution ty
60 return $ varIfUnknown ty
62allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
63allUnknownsBecameQuantified cs solution ty = do
65 typesMentioned = findUnknownTypes ty
66 unknownTypes = nub $ flip concatMap cs $ \c -> case c of
67 TypeConstraint u t -> u : findUnknownTypes t
68 RowConstraint _ r -> findUnknownTypes r
69 unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes
70 guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned
72 rowsMentioned = findUnknownRows ty
73 unknownRows = nub $ flip concatMap cs $ \c -> case c of
74 TypeConstraint _ t -> findUnknownRows t
75 RowConstraint u r -> u : findUnknownRows r
76 unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
77 guardWith ("Unsolved row variable" ++ show (unsolvedRows \\ rowsMentioned) ++ ", " ++ show cs) $ null $ unsolvedRows \\ rowsMentioned
79findUnknownTypes :: (Data d) => d -> [Int]
80findUnknownTypes = everything (++) (mkQ [] f)
86findTypeVars :: (Data d) => d -> [String]
87findTypeVars = everything (++) (mkQ [] f)
93findUnknownRows :: (Data d) => d -> [Int]
94findUnknownRows = everything (++) (mkQ [] f)
100varIfUnknown :: Type -> PolyType
103 (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty
105 PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'
107 f :: Type -> State (M.Map Int String) Type
112 let name = "t" ++ show (M.size m)
113 put $ M.insert n name m
114 return $ TypeVar name
115 Just name -> return $ TypeVar name
117 g :: Row -> State (M.Map Int String) Row
122 let name = "r" ++ show (M.size m)
123 put $ M.insert n name m
125 Just name -> return $ RowVar name
128replaceVarsWithUnknowns :: [String] -> Type -> Check Type
129replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)
131 f :: Type -> StateT (M.Map String Int) Check Type
132 f (TypeVar var) | var `elem` idents = do
135 case M.lookup var m of
137 put (M.insert var n m)
139 Just u -> return $ TUnknown u
141 g :: Row -> StateT (M.Map String Int) Check Row
142 g (RowVar var) | var `elem` idents = do
145 case M.lookup var m of
147 put (M.insert var n m)
149 Just u -> return $ RUnknown u
152replaceType :: (Data d) => Int -> Type -> d -> d
153replaceType n t = everywhere (mkT go)
155 go (TUnknown m) | m == n = t
158replaceRow :: (Data d) => Int -> Row -> d -> d
159replaceRow n r = everywhere (mkT go)
161 go (RUnknown m) | m == n = r
164typeOccursCheck :: Int -> Type -> Check ()
165typeOccursCheck u (TUnknown _) = return ()
166typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ show t
168rowOccursCheck :: Int -> Row -> Check ()
169rowOccursCheck u (RUnknown _) = return ()
170rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ show r
172occursCheck :: (Data d) => Int -> d -> Bool
173occursCheck u = everything (||) $ flip extQ g $ mkQ False f
175 f (TUnknown u') | u' == u = True
177 g (RUnknown u') | u' == u = True
180typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
181typeConstraints _ (NumericLiteral _) = do
183 return ([TypeConstraint me Number], me)
184typeConstraints _ (StringLiteral _) = do
186 return ([TypeConstraint me String], me)
187typeConstraints _ (BooleanLiteral _) = do
189 return ([TypeConstraint me Boolean], me)
190typeConstraints m (ArrayLiteral vals) = do
191 all <- mapM (typeConstraints m) vals
192 let (cs, ns) = (concat . map fst &&& map snd) all
194 return (cs ++ map (TypeConstraint me . Array . TUnknown) ns, me)
195typeConstraints m (Unary op val) = do
196 (cs, n1) <- typeConstraints m val
198 return (cs ++ unaryOperatorConstraints op n1 me, me)
199typeConstraints m (Binary op left right) = do
200 (cs1, n1) <- typeConstraints m left
201 (cs2, n2) <- typeConstraints m right
203 return (cs1 ++ cs2 ++ binaryOperatorConstraints op n1 n2 me, me)
204typeConstraints m (ObjectLiteral ps) = do
205 all <- mapM (typeConstraints m . snd) ps
206 let (cs, ns) = (concat . map fst &&& map snd) all
208 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
209 return ((TypeConstraint me (Object (typesToRow tys))) : cs, me)
211 typesToRow [] = REmpty
212 typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
213typeConstraints m (Indexer index val) = do
214 (cs1, n1) <- typeConstraints m index
215 (cs2, n2) <- typeConstraints m val
217 return ((TypeConstraint n1 Number) : (TypeConstraint n2 (Array (TUnknown me))) : cs1 ++ cs2, me)
218typeConstraints m (Accessor prop val) = do
219 (cs, n1) <- typeConstraints m val
222 return ((TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest)))) : cs, me)
223typeConstraints m (Abs args ret) = do
224 ns <- replicateM (length args) fresh
225 let m' = m `M.union` M.fromList (zipWith (,) args ns)
226 (cs, n') <- typeConstraints m' ret
228 return ((TypeConstraint me (Function (map TUnknown ns) (TUnknown n'))) : cs, me)
229typeConstraints m (App f xs) = do
230 (cs1, n1) <- typeConstraints m f
231 all <- mapM (typeConstraints m) xs
232 let (cs2, ns) = (concat . map fst &&& map snd) all
234 return ((TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me))) : cs1 ++ cs2, me)
235typeConstraints m (Var var) =
236 case M.lookup var m of
239 case M.lookup var (names env) of
240 Nothing -> throwError $ show var ++ " is undefined"
241 Just (PolyType idents ty, _) -> do
243 replaced <- replaceVarsWithUnknowns idents ty
244 return ([TypeConstraint me replaced], me)
247 return ([TypeConstraint u (TUnknown me)], me)
248typeConstraints m (Block ss) = do
250 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
251 guardWith "Block is missing a return statement" allCodePathsReturn
253typeConstraints m (Constructor c) = do
255 case M.lookup c (dataConstructors env) of
256 Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"
257 Just (PolyType idents ty) -> do
259 replaced <- replaceVarsWithUnknowns idents ty
260 return ([TypeConstraint me replaced], me)
261typeConstraints m (Case val binders) = do
262 (cs1, n1) <- typeConstraints m val
264 cs2 <- typeConstraintsForBinders m n1 ret binders
265 return (cs1 ++ cs2, ret)
266typeConstraints m (TypedValue val poly@(PolyType idents ty)) = do
268 guardWith ("Expected type of kind *, was " ++ show kind) $ kind == Star
269 desugared <- replaceAllTypeSynonyms ty
270 (cs, n1) <- typeConstraints m val
271 return (TypeConstraint n1 desugared : cs, n1)
273replaceAllTypeSynonyms :: Type -> Check Type
274replaceAllTypeSynonyms ty = do
276 go (M.toList $ typeSynonyms env) ty
279 go ((name, (args, repl)):rest) ty = do
280 ty' <- either throwError return (substituteTypeSynonym name args repl ty)
283unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
284unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
285unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
286unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
288binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
289binaryOperatorConstraints Add = symBinOpConstraints Number
290binaryOperatorConstraints Subtract = symBinOpConstraints Number
291binaryOperatorConstraints Multiply = symBinOpConstraints Number
292binaryOperatorConstraints Divide = symBinOpConstraints Number
293binaryOperatorConstraints Modulus = symBinOpConstraints Number
294binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
295binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
296binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
297binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
298binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
299binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
300binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
301binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
302binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
303binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
304binaryOperatorConstraints EqualTo = equalityBinOpConstraints
305binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
306binaryOperatorConstraints And = symBinOpConstraints Boolean
307binaryOperatorConstraints Or = symBinOpConstraints Boolean
308binaryOperatorConstraints Concat = symBinOpConstraints String
310equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
311equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
313symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
314symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
316asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
317asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
319typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
320typeConstraintsForBinder _ NullBinder = return ([], M.empty)
321typeConstraintsForBinder val (StringBinder _) = constantBinder val String
322typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
323typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
324typeConstraintsForBinder val (VarBinder name) = do
326 return ([TypeConstraint me (TUnknown val)], M.singleton name me)
327typeConstraintsForBinder val (NullaryBinder ctor) = do
329 case M.lookup ctor (dataConstructors env) of
330 Just (PolyType args ret) -> do
331 ret' <- replaceVarsWithUnknowns args ret
332 return ([TypeConstraint val ret'], M.empty)
333 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
334typeConstraintsForBinder val (UnaryBinder ctor binder) = do
336 case M.lookup ctor (dataConstructors env) of
337 Just (PolyType idents f@(Function [_] _)) -> do
339 (Function [ty] ret) <- replaceVarsWithUnknowns idents f
340 (cs, m1) <- typeConstraintsForBinder obj binder
341 return ((TypeConstraint val ret) : (TypeConstraint obj ty) : cs, m1)
342 Just _ -> throwError $ ctor ++ " is not a unary constructor"
343 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
344typeConstraintsForBinder val (ObjectBinder props) = do
347 (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
348 return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
350 typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
351 typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
352 typeConstraintsForProperties nrow row ((name, binder):binders) = do
354 (cs1, m1) <- typeConstraintsForBinder propTy binder
355 (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
356 return (cs1 ++ cs2, M.union m1 m2)
357typeConstraintsForBinder val (ArrayBinder binders rest) = do
359 all <- mapM (typeConstraintsForBinder el) binders
360 let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
361 let arrayConstraint = TypeConstraint val (Array (TUnknown el))
363 Nothing -> return (arrayConstraint : cs1, m1)
365 (cs2, m2) <- typeConstraintsForBinder val binder
366 return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
367typeConstraintsForBinder val (NamedBinder name binder) = do
369 (cs, m) <- typeConstraintsForBinder val binder
370 return (TypeConstraint me (TUnknown val) : cs, M.insert name me m)
371typeConstraintsForBinder val (GuardedBinder cond binder) = do
372 (cs1, m) <- typeConstraintsForBinder val binder
373 (cs2, n) <- typeConstraints m cond
374 return (TypeConstraint n Boolean : cs1 ++ cs2, m)
376constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
377constantBinder val ty = return ([TypeConstraint val ty], M.empty)
379typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
380typeConstraintsForBinders _ _ _ [] = return []
381typeConstraintsForBinders m nval ret ((binder, val):bs) = do
382 (cs1, m1) <- typeConstraintsForBinder nval binder
383 (cs2, n2) <- typeConstraints (M.union m m1) val
384 cs3 <- typeConstraintsForBinders m nval ret bs
385 return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
387assignVariable :: Ident -> M.Map Ident Int -> Check ()
388assignVariable name m =
389 case M.lookup name m of
391 Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
393typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
394typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
395 assignVariable name (m `M.union` mass)
396 (cs1, n1) <- typeConstraints m val
397 return $ (cs1, False, M.insert name n1 mass)
398typeConstraintsForStatement m mass ret (Assignment tgt val) = do
399 (cs1, n1) <- typeConstraints m val
400 cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
401 return (cs1 ++ cs2, False, mass)
402typeConstraintsForStatement m mass ret (While val inner) = do
403 (cs1, n1) <- typeConstraints m val
404 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
405 return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
406typeConstraintsForStatement m mass ret (If ifst) = do
407 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
408 return $ (cs, allCodePathsReturn, mass)
409typeConstraintsForStatement m mass ret (For ident start end inner) = do
410 assignVariable ident (m `M.union` mass)
411 (cs1, n1) <- typeConstraints (m `M.union` mass) start
412 (cs2, n2) <- typeConstraints (m `M.union` mass) end
413 let mass1 = M.insert ident n1 mass
414 (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
415 return $ ((TypeConstraint n1 Number) : (TypeConstraint n2 Number) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
416typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
417 assignVariable ident (m `M.union` mass)
419 (cs1, n1) <- typeConstraints (m `M.union` mass) vals
420 let mass1 = M.insert ident val mass
421 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
422 guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
423 return $ ((TypeConstraint n1 (Array (TUnknown val))) : cs1 ++ cs2, False, mass)
424typeConstraintsForStatement m mass ret (Return val) = do
425 (cs1, n1) <- typeConstraints (m `M.union` mass) val
426 return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
428typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
429typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
430 (cs1, n1) <- typeConstraints m val
431 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
432 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn)
433typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
434 (cs1, n1) <- typeConstraints m val
435 (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
436 (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
437 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
439typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
440typeConstraintsForElseStatement m mass ret (Else elses) = do
441 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
442 return (cs, allCodePathsReturn)
443typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
444 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
445 return (cs, allCodePathsReturn)
447typeConstraintsForAssignmentTarget :: M.Map Ident Int -> M.Map Ident Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
448typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
449 case M.lookup var mass of
450 Nothing -> throwError $ "No local variable with name " ++ show var
452 return [TypeConstraint nval (TUnknown ty)]
453typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
455 (cs1, n1) <- typeConstraints (m `M.union` mass) index
456 cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
457 return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
458typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
461 cs <- typeConstraintsForAssignmentTarget m mass obj tgt
462 return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
464typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
465typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
466typeConstraintsForBlock m mass ret (s:ss) = do
467 (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
469 (True, []) -> return (cs1, True, mass1)
470 (True, _) -> throwError "Unreachable code"
472 (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
473 return (cs1 ++ cs2, b2, mass2)
475solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
476solveTypeConstraints [] s = return s
477solveTypeConstraints all@(TypeConstraint n t:cs) s = do
479 let s' = let (f, g) = runTypeSolution s
480 in TypeSolution (replaceType n t . f, replaceType n t . g)
481 cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
482 solveTypeConstraints cs' s'
483solveTypeConstraints (RowConstraint n r:cs) s = do
485 let s' = let (f, g) = runTypeSolution s
486 in TypeSolution $ (replaceRow n r . f, replaceRow n r . g)
487 cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
488 solveTypeConstraints cs' s'
490substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
491substituteTypeInConstraint n s (TypeConstraint m t)
492 | n == m = unifyTypes s t
493 | otherwise = return [TypeConstraint m (replaceType n s t)]
494substituteTypeInConstraint n s (RowConstraint m r)
495 = return [RowConstraint m (replaceType n s r)]
497substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
498substituteRowInConstraint n r (TypeConstraint m t)
499 = return [TypeConstraint m (replaceRow n r t)]
500substituteRowInConstraint n r (RowConstraint m r1)
501 | m == n = unifyRows r r1
502 | otherwise = return [RowConstraint m (replaceRow n r r1)]
504unifyTypes :: Type -> Type -> Check [TypeConstraint]
505unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
506unifyTypes (TUnknown u) t = do
508 return [TypeConstraint u t]
509unifyTypes t (TUnknown u) = do
511 return [TypeConstraint u t]
512unifyTypes Number Number = return []
513unifyTypes String String = return []
514unifyTypes Boolean Boolean = return []
515unifyTypes (Array s) (Array t) = unifyTypes s t
516unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
517unifyTypes (Function args1 ret1) (Function args2 ret2) = do
518 guardWith "Function applied to incorrect number of args" $ length args1 == length args2
519 cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
520 cs2 <- unifyTypes ret1 ret2
522unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
523unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
524unifyTypes (TypeVar v1) (TypeVar v2) = return []
525unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
526 cs1 <- unifyTypes t1 t3
527 cs2 <- unifyTypes t2 t4
529unifyTypes t1 t2 = throwError $ "Cannot unify " ++ show t1 ++ " with " ++ show t2 ++ "."
531unifyRows :: Row -> Row -> Check [TypeConstraint]
534 (s1, r1') = toList r1
535 (s2, r2') = toList r2
536 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
537 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
538 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
539 in rethrow (\e -> "Cannot unify " ++ show r1 ++ " with " ++ show r2 ++ ": " ++ e) $ do
540 cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
541 cs2 <- unifyRows' sd1 r1' sd2 r2'
544 unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
545 unifyRows' [] (RUnknown u) sd r = do
547 return [RowConstraint u (fromList (sd, r))]
548 unifyRows' sd r [] (RUnknown u) = do
550 return [RowConstraint u (fromList (sd, r))]
551 unifyRows' ((name, ty):row) r others (RUnknown u) = do
553 cs <- unifyRows' row r others (RUnknown u')
554 return (RowConstraint u (RCons name ty (RUnknown u')) : cs)
555 unifyRows' [] REmpty [] REmpty = return []
556 unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ show (fromList (sd1, r1)) ++ " with " ++ show (fromList (sd2, r2)) ++ "."
557 toList :: Row -> ([(String, Type)], Row)
558 toList (RCons name ty row) = let (tys, rest) = toList row
559 in ((name, ty):tys, rest)
561 fromList :: ([(String, Type)], Row) -> Row
563 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