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 (IfThenElse cond th el) = do
270 (cs1, n1) <- typeConstraints m cond
271 (cs2, n2) <- typeConstraints m th
272 (cs3, n3) <- typeConstraints m el
273 return (TypeConstraint n1 Boolean : TypeConstraint n2 (TUnknown n3) : cs1 ++ cs2 ++ cs3, n2)
274typeConstraints m (TypedValue val poly@(PolyType idents ty)) = do
276 guardWith ("Expected type of kind *, was " ++ show kind) $ kind == Star
277 desugared <- replaceAllTypeSynonyms ty
278 (cs, n1) <- typeConstraints m val
279 return (TypeConstraint n1 desugared : cs, n1)
281replaceAllTypeSynonyms :: Type -> Check Type
282replaceAllTypeSynonyms ty = do
284 go (M.toList $ typeSynonyms env) ty
287 go ((name, (args, repl)):rest) ty = do
288 ty' <- either throwError return (substituteTypeSynonym name args repl ty)
291unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
292unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
293unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
294unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
296binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
297binaryOperatorConstraints Add = symBinOpConstraints Number
298binaryOperatorConstraints Subtract = symBinOpConstraints Number
299binaryOperatorConstraints Multiply = symBinOpConstraints Number
300binaryOperatorConstraints Divide = symBinOpConstraints Number
301binaryOperatorConstraints Modulus = symBinOpConstraints Number
302binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
303binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
304binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
305binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
306binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
307binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
308binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
309binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
310binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
311binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
312binaryOperatorConstraints EqualTo = equalityBinOpConstraints
313binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
314binaryOperatorConstraints And = symBinOpConstraints Boolean
315binaryOperatorConstraints Or = symBinOpConstraints Boolean
316binaryOperatorConstraints Concat = symBinOpConstraints String
318equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
319equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
321symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
322symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
324asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
325asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
327typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
328typeConstraintsForBinder _ NullBinder = return ([], M.empty)
329typeConstraintsForBinder val (StringBinder _) = constantBinder val String
330typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
331typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
332typeConstraintsForBinder val (VarBinder name) = do
334 return ([TypeConstraint me (TUnknown val)], M.singleton name me)
335typeConstraintsForBinder val (NullaryBinder ctor) = do
337 case M.lookup ctor (dataConstructors env) of
338 Just (PolyType args ret) -> do
339 ret' <- replaceVarsWithUnknowns args ret
340 return ([TypeConstraint val ret'], M.empty)
341 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
342typeConstraintsForBinder val (UnaryBinder ctor binder) = do
344 case M.lookup ctor (dataConstructors env) of
345 Just (PolyType idents f@(Function [_] _)) -> do
347 (Function [ty] ret) <- replaceVarsWithUnknowns idents f
348 (cs, m1) <- typeConstraintsForBinder obj binder
349 return ((TypeConstraint val ret) : (TypeConstraint obj ty) : cs, m1)
350 Just _ -> throwError $ ctor ++ " is not a unary constructor"
351 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
352typeConstraintsForBinder val (ObjectBinder props) = do
355 (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
356 return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
358 typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
359 typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
360 typeConstraintsForProperties nrow row ((name, binder):binders) = do
362 (cs1, m1) <- typeConstraintsForBinder propTy binder
363 (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
364 return (cs1 ++ cs2, M.union m1 m2)
365typeConstraintsForBinder val (ArrayBinder binders rest) = do
367 all <- mapM (typeConstraintsForBinder el) binders
368 let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
369 let arrayConstraint = TypeConstraint val (Array (TUnknown el))
371 Nothing -> return (arrayConstraint : cs1, m1)
373 (cs2, m2) <- typeConstraintsForBinder val binder
374 return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
375typeConstraintsForBinder val (NamedBinder name binder) = do
377 (cs, m) <- typeConstraintsForBinder val binder
378 return (TypeConstraint me (TUnknown val) : cs, M.insert name me m)
379typeConstraintsForBinder val (GuardedBinder cond binder) = do
380 (cs1, m) <- typeConstraintsForBinder val binder
381 (cs2, n) <- typeConstraints m cond
382 return (TypeConstraint n Boolean : cs1 ++ cs2, m)
384constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
385constantBinder val ty = return ([TypeConstraint val ty], M.empty)
387typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
388typeConstraintsForBinders _ _ _ [] = return []
389typeConstraintsForBinders m nval ret ((binder, val):bs) = do
390 (cs1, m1) <- typeConstraintsForBinder nval binder
391 (cs2, n2) <- typeConstraints (M.union m m1) val
392 cs3 <- typeConstraintsForBinders m nval ret bs
393 return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
395assignVariable :: Ident -> M.Map Ident Int -> Check ()
396assignVariable name m =
397 case M.lookup name m of
399 Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
401typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
402typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
403 assignVariable name (m `M.union` mass)
404 (cs1, n1) <- typeConstraints m val
405 return $ (cs1, False, M.insert name n1 mass)
406typeConstraintsForStatement m mass ret (Assignment tgt val) = do
407 (cs1, n1) <- typeConstraints m val
408 cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
409 return (cs1 ++ cs2, False, mass)
410typeConstraintsForStatement m mass ret (While val inner) = do
411 (cs1, n1) <- typeConstraints m val
412 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
413 return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
414typeConstraintsForStatement m mass ret (If ifst) = do
415 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
416 return $ (cs, allCodePathsReturn, mass)
417typeConstraintsForStatement m mass ret (For ident start end inner) = do
418 assignVariable ident (m `M.union` mass)
419 (cs1, n1) <- typeConstraints (m `M.union` mass) start
420 (cs2, n2) <- typeConstraints (m `M.union` mass) end
421 let mass1 = M.insert ident n1 mass
422 (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
423 return $ ((TypeConstraint n1 Number) : (TypeConstraint n2 Number) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
424typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
425 assignVariable ident (m `M.union` mass)
427 (cs1, n1) <- typeConstraints (m `M.union` mass) vals
428 let mass1 = M.insert ident val mass
429 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
430 guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
431 return $ ((TypeConstraint n1 (Array (TUnknown val))) : cs1 ++ cs2, False, mass)
432typeConstraintsForStatement m mass ret (Return val) = do
433 (cs1, n1) <- typeConstraints (m `M.union` mass) val
434 return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
436typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
437typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
438 (cs1, n1) <- typeConstraints m val
439 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
440 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn)
441typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
442 (cs1, n1) <- typeConstraints m val
443 (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
444 (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
445 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
447typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
448typeConstraintsForElseStatement m mass ret (Else elses) = do
449 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
450 return (cs, allCodePathsReturn)
451typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
452 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
453 return (cs, allCodePathsReturn)
455typeConstraintsForAssignmentTarget :: M.Map Ident Int -> M.Map Ident Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
456typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
457 case M.lookup var mass of
458 Nothing -> throwError $ "No local variable with name " ++ show var
460 return [TypeConstraint nval (TUnknown ty)]
461typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
463 (cs1, n1) <- typeConstraints (m `M.union` mass) index
464 cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
465 return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
466typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
469 cs <- typeConstraintsForAssignmentTarget m mass obj tgt
470 return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
472typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
473typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
474typeConstraintsForBlock m mass ret (s:ss) = do
475 (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
477 (True, []) -> return (cs1, True, mass1)
478 (True, _) -> throwError "Unreachable code"
480 (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
481 return (cs1 ++ cs2, b2, mass2)
483solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
484solveTypeConstraints [] s = return s
485solveTypeConstraints all@(TypeConstraint n t:cs) s = do
487 let s' = let (f, g) = runTypeSolution s
488 in TypeSolution (replaceType n t . f, replaceType n t . g)
489 cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
490 solveTypeConstraints cs' s'
491solveTypeConstraints (RowConstraint n r:cs) s = do
493 let s' = let (f, g) = runTypeSolution s
494 in TypeSolution $ (replaceRow n r . f, replaceRow n r . g)
495 cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
496 solveTypeConstraints cs' s'
498substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
499substituteTypeInConstraint n s (TypeConstraint m t)
500 | n == m = unifyTypes s t
501 | otherwise = return [TypeConstraint m (replaceType n s t)]
502substituteTypeInConstraint n s (RowConstraint m r)
503 = return [RowConstraint m (replaceType n s r)]
505substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
506substituteRowInConstraint n r (TypeConstraint m t)
507 = return [TypeConstraint m (replaceRow n r t)]
508substituteRowInConstraint n r (RowConstraint m r1)
509 | m == n = unifyRows r r1
510 | otherwise = return [RowConstraint m (replaceRow n r r1)]
512unifyTypes :: Type -> Type -> Check [TypeConstraint]
513unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
514unifyTypes (TUnknown u) t = do
516 return [TypeConstraint u t]
517unifyTypes t (TUnknown u) = do
519 return [TypeConstraint u t]
520unifyTypes Number Number = return []
521unifyTypes String String = return []
522unifyTypes Boolean Boolean = return []
523unifyTypes (Array s) (Array t) = unifyTypes s t
524unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
525unifyTypes (Function args1 ret1) (Function args2 ret2) = do
526 guardWith "Function applied to incorrect number of args" $ length args1 == length args2
527 cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
528 cs2 <- unifyTypes ret1 ret2
530unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
531unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
532unifyTypes (TypeVar v1) (TypeVar v2) = return []
533unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
534 cs1 <- unifyTypes t1 t3
535 cs2 <- unifyTypes t2 t4
537unifyTypes t1 t2 = throwError $ "Cannot unify " ++ show t1 ++ " with " ++ show t2 ++ "."
539unifyRows :: Row -> Row -> Check [TypeConstraint]
542 (s1, r1') = toList r1
543 (s2, r2') = toList r2
544 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
545 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
546 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
547 in rethrow (\e -> "Cannot unify " ++ show r1 ++ " with " ++ show r2 ++ ": " ++ e) $ do
548 cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
549 cs2 <- unifyRows' sd1 r1' sd2 r2'
552 unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
553 unifyRows' [] (RUnknown u) sd r = do
555 return [RowConstraint u (fromList (sd, r))]
556 unifyRows' sd r [] (RUnknown u) = do
558 return [RowConstraint u (fromList (sd, r))]
559 unifyRows' ((name, ty):row) r others (RUnknown u) = do
561 cs <- unifyRows' row r others (RUnknown u')
562 return (RowConstraint u (RCons name ty (RUnknown u')) : cs)
563 unifyRows' [] REmpty [] REmpty = return []
564 unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ show (fromList (sd1, r1)) ++ " with " ++ show (fromList (sd2, r2)) ++ "."
565 toList :: Row -> ([(String, Type)], Row)
566 toList (RCons name ty row) = let (tys, rest) = toList row
567 in ((name, ty):tys, rest)
569 fromList :: ([(String, Type)], Row) -> Row
571 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