1-----------------------------------------------------------------------------
3-- Module : PureScript.TypeChecker.Types
4-- Copyright : (c) Phil Freeman 2013
7-- Maintainer : Phil Freeman <paf31@cantab.net>
8-- Stability : experimental
13-----------------------------------------------------------------------------
15{-# LANGUAGE DeriveDataTypeable #-}
17module PureScript.TypeChecker.Types (
25import qualified Data.Data as D
26import Data.Generics (everywhere, everywhereM, everything, mkT, mkM, mkQ, extM, extQ)
28import PureScript.Values
29import PureScript.Types
30import PureScript.Kinds
31import PureScript.Names
32import PureScript.TypeChecker.Monad
33import PureScript.TypeChecker.Kinds
34import PureScript.TypeChecker.Synonyms
35import PureScript.CodeGen.Pretty.Types
36import PureScript.CodeGen.Pretty.Kinds
38import Control.Monad.State
39import Control.Monad.Error
41import Control.Applicative
42import Control.Arrow (Kleisli(..), (***), (&&&))
43import qualified Control.Category as C
45import qualified Data.Map as M
48 = TypeConstraint Int Type
49 | RowConstraint Int Row deriving (Show, D.Data, D.Typeable)
51newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }
53emptyTypeSolution :: TypeSolution
54emptyTypeSolution = TypeSolution (TUnknown, RUnknown)
56typeOf :: Ident -> Value -> Check PolyType
58 (cs, n) <- case val of
61 (cs, n) <- typeConstraints (M.singleton name me) val
62 return (TypeConstraint me (TUnknown n) : cs, n)
63 _ -> typeConstraints M.empty val
64 desugared <- replaceAllTypeSynonyms cs
65 solution <- solveTypeConstraints desugared emptyTypeSolution
66 let ty = fst (runTypeSolution solution) n
67 allUnknownsBecameQuantified desugared solution ty
68 return $ varIfUnknown ty
70allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
71allUnknownsBecameQuantified cs solution ty = do
73 typesMentioned = findUnknownTypes ty
74 unknownTypes = nub $ flip concatMap cs $ \c -> case c of
75 TypeConstraint u t -> u : findUnknownTypes t
76 RowConstraint _ r -> findUnknownTypes r
77 unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes
78 guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned
80 rowsMentioned = findUnknownRows ty
81 unknownRows = nub $ flip concatMap cs $ \c -> case c of
82 TypeConstraint _ t -> findUnknownRows t
83 RowConstraint u r -> u : findUnknownRows r
84 unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
85 guardWith "Unsolved row variable" $ null $ unsolvedRows \\ rowsMentioned
87findUnknownTypes :: (D.Data d) => d -> [Int]
88findUnknownTypes = everything (++) (mkQ [] f)
94findTypeVars :: (D.Data d) => d -> [String]
95findTypeVars = everything (++) (mkQ [] f)
101findUnknownRows :: (D.Data d) => d -> [Int]
102findUnknownRows = everything (++) (mkQ [] f)
108varIfUnknown :: Type -> PolyType
111 (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty
113 PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'
115 f :: Type -> State (M.Map Int String) Type
120 let name = "t" ++ show (M.size m)
121 put $ M.insert n name m
122 return $ TypeVar name
123 Just name -> return $ TypeVar name
125 g :: Row -> State (M.Map Int String) Row
130 let name = "r" ++ show (M.size m)
131 put $ M.insert n name m
133 Just name -> return $ RowVar name
136replaceVarsWithUnknowns :: [String] -> Type -> Check Type
137replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)
139 f :: Type -> StateT (M.Map String Int) Check Type
140 f (TypeVar var) | var `elem` idents = do
143 case M.lookup var m of
145 put (M.insert var n m)
147 Just u -> return $ TUnknown u
149 g :: Row -> StateT (M.Map String Int) Check Row
150 g (RowVar var) | var `elem` idents = do
153 case M.lookup var m of
155 put (M.insert var n m)
157 Just u -> return $ RUnknown u
160replaceAllTypeSynonyms :: (D.Data d) => d -> Check d
161replaceAllTypeSynonyms ty = do
163 go (M.toList $ typeSynonyms env) ty
166 go ((name, (args, repl)):rest) d = do
167 d' <- either throwError return (substituteTypeSynonym name args repl d)
170replaceType :: (D.Data d) => Int -> Type -> d -> d
171replaceType n t = everywhere (mkT go)
173 go (TUnknown m) | m == n = t
176replaceRow :: (D.Data d) => Int -> Row -> d -> d
177replaceRow n r = everywhere (mkT go)
179 go (RUnknown m) | m == n = r
182typeOccursCheck :: Int -> Type -> Check ()
183typeOccursCheck u (TUnknown _) = return ()
184typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintType t
186rowOccursCheck :: Int -> Row -> Check ()
187rowOccursCheck u (RUnknown _) = return ()
188rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintRow r
190occursCheck :: (D.Data d) => Int -> d -> Bool
191occursCheck u = everything (||) $ flip extQ g $ mkQ False f
193 f (TUnknown u') | u' == u = True
195 g (RUnknown u') | u' == u = True
198typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
199typeConstraints _ (NumericLiteral _) = do
201 return ([TypeConstraint me Number], me)
202typeConstraints _ (StringLiteral _) = do
204 return ([TypeConstraint me String], me)
205typeConstraints _ (BooleanLiteral _) = do
207 return ([TypeConstraint me Boolean], me)
208typeConstraints m (ArrayLiteral vals) = do
209 all <- mapM (typeConstraints m) vals
210 let (cs, ns) = (concat . map fst &&& map snd) all
212 return (cs ++ map (TypeConstraint me . Array . TUnknown) ns, me)
213typeConstraints m (Unary op val) = do
214 (cs, n1) <- typeConstraints m val
216 return (cs ++ unaryOperatorConstraints op n1 me, me)
217typeConstraints m (Binary op left right) = do
218 (cs1, n1) <- typeConstraints m left
219 (cs2, n2) <- typeConstraints m right
221 return (cs1 ++ cs2 ++ binaryOperatorConstraints op n1 n2 me, me)
222typeConstraints m (ObjectLiteral ps) = do
223 all <- mapM (typeConstraints m . snd) ps
224 let (cs, ns) = (concat . map fst &&& map snd) all
226 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
227 return ((TypeConstraint me (Object (typesToRow tys))) : cs, me)
229 typesToRow [] = REmpty
230 typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
231typeConstraints m (Indexer index val) = do
232 (cs1, n1) <- typeConstraints m index
233 (cs2, n2) <- typeConstraints m val
235 return ((TypeConstraint n1 Number) : (TypeConstraint n2 (Array (TUnknown me))) : cs1 ++ cs2, me)
236typeConstraints m (Accessor prop val) = do
237 (cs, n1) <- typeConstraints m val
240 return ((TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest)))) : cs, me)
241typeConstraints m (Abs args ret) = do
242 ns <- replicateM (length args) fresh
243 let m' = m `M.union` M.fromList (zipWith (,) args ns)
244 (cs, n') <- typeConstraints m' ret
246 return ((TypeConstraint me (Function (map TUnknown ns) (TUnknown n'))) : cs, me)
247typeConstraints m (App f xs) = do
248 (cs1, n1) <- typeConstraints m f
249 all <- mapM (typeConstraints m) xs
250 let (cs2, ns) = (concat . map fst &&& map snd) all
252 return ((TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me))) : cs1 ++ cs2, me)
253typeConstraints m (Var var) =
254 case M.lookup var m of
257 case M.lookup var (names env) of
258 Nothing -> throwError $ show var ++ " is undefined"
259 Just (PolyType idents ty, _) -> do
261 replaced <- replaceVarsWithUnknowns idents ty
262 return ([TypeConstraint me replaced], me)
265 return ([TypeConstraint u (TUnknown me)], me)
266typeConstraints m (Block ss) = do
268 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
269 guardWith "Block is missing a return statement" allCodePathsReturn
271typeConstraints m (Constructor c) = do
273 case M.lookup c (dataConstructors env) of
274 Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"
275 Just (PolyType idents ty) -> do
277 replaced <- replaceVarsWithUnknowns idents ty
278 return ([TypeConstraint me replaced], me)
279typeConstraints m (Case val binders) = do
280 (cs1, n1) <- typeConstraints m val
282 cs2 <- typeConstraintsForBinders m n1 ret binders
283 return (cs1 ++ cs2, ret)
284typeConstraints m (IfThenElse cond th el) = do
285 (cs1, n1) <- typeConstraints m cond
286 (cs2, n2) <- typeConstraints m th
287 (cs3, n3) <- typeConstraints m el
288 return (TypeConstraint n1 Boolean : TypeConstraint n2 (TUnknown n3) : cs1 ++ cs2 ++ cs3, n2)
289typeConstraints m (TypedValue val poly@(PolyType idents ty)) = do
291 guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
292 (cs, n1) <- typeConstraints m val
293 return (TypeConstraint n1 ty : cs, n1)
295unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
296unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
297unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
298unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
300binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
301binaryOperatorConstraints Add = symBinOpConstraints Number
302binaryOperatorConstraints Subtract = symBinOpConstraints Number
303binaryOperatorConstraints Multiply = symBinOpConstraints Number
304binaryOperatorConstraints Divide = symBinOpConstraints Number
305binaryOperatorConstraints Modulus = symBinOpConstraints Number
306binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
307binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
308binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
309binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
310binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
311binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
312binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
313binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
314binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
315binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
316binaryOperatorConstraints EqualTo = equalityBinOpConstraints
317binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
318binaryOperatorConstraints And = symBinOpConstraints Boolean
319binaryOperatorConstraints Or = symBinOpConstraints Boolean
320binaryOperatorConstraints Concat = symBinOpConstraints String
322equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
323equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
325symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
326symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
328asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
329asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
331typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
332typeConstraintsForBinder _ NullBinder = return ([], M.empty)
333typeConstraintsForBinder val (StringBinder _) = constantBinder val String
334typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
335typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
336typeConstraintsForBinder val (VarBinder name) = do
338 return ([TypeConstraint me (TUnknown val)], M.singleton name me)
339typeConstraintsForBinder val (NullaryBinder ctor) = do
341 case M.lookup ctor (dataConstructors env) of
342 Just (PolyType args ret) -> do
343 ret' <- replaceVarsWithUnknowns args ret
344 return ([TypeConstraint val ret'], M.empty)
345 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
346typeConstraintsForBinder val (UnaryBinder ctor binder) = do
348 case M.lookup ctor (dataConstructors env) of
349 Just (PolyType idents f@(Function [_] _)) -> do
351 (Function [ty] ret) <- replaceVarsWithUnknowns idents f
352 (cs, m1) <- typeConstraintsForBinder obj binder
353 return ((TypeConstraint val ret) : (TypeConstraint obj ty) : cs, m1)
354 Just _ -> throwError $ ctor ++ " is not a unary constructor"
355 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
356typeConstraintsForBinder val (ObjectBinder props) = do
359 (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
360 return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
362 typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
363 typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
364 typeConstraintsForProperties nrow row ((name, binder):binders) = do
366 (cs1, m1) <- typeConstraintsForBinder propTy binder
367 (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
368 return (cs1 ++ cs2, M.union m1 m2)
369typeConstraintsForBinder val (ArrayBinder binders rest) = do
371 all <- mapM (typeConstraintsForBinder el) binders
372 let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
373 let arrayConstraint = TypeConstraint val (Array (TUnknown el))
375 Nothing -> return (arrayConstraint : cs1, m1)
377 (cs2, m2) <- typeConstraintsForBinder val binder
378 return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
379typeConstraintsForBinder val (NamedBinder name binder) = do
381 (cs, m) <- typeConstraintsForBinder val binder
382 return (TypeConstraint me (TUnknown val) : cs, M.insert name me m)
383typeConstraintsForBinder val (GuardedBinder cond binder) = do
384 (cs1, m) <- typeConstraintsForBinder val binder
385 (cs2, n) <- typeConstraints m cond
386 return (TypeConstraint n Boolean : cs1 ++ cs2, m)
388constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
389constantBinder val ty = return ([TypeConstraint val ty], M.empty)
391typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
392typeConstraintsForBinders _ _ _ [] = return []
393typeConstraintsForBinders m nval ret ((binder, val):bs) = do
394 (cs1, m1) <- typeConstraintsForBinder nval binder
395 (cs2, n2) <- typeConstraints (M.union m m1) val
396 cs3 <- typeConstraintsForBinders m nval ret bs
397 return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
399assignVariable :: Ident -> M.Map Ident Int -> Check ()
400assignVariable name m =
401 case M.lookup name m of
403 Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
405typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
406typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
407 assignVariable name (m `M.union` mass)
408 (cs1, n1) <- typeConstraints m val
409 return $ (cs1, False, M.insert name n1 mass)
410typeConstraintsForStatement m mass ret (Assignment tgt val) = do
411 (cs1, n1) <- typeConstraints m val
412 cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
413 return (cs1 ++ cs2, False, mass)
414typeConstraintsForStatement m mass ret (While val inner) = do
415 (cs1, n1) <- typeConstraints m val
416 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
417 return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
418typeConstraintsForStatement m mass ret (If ifst) = do
419 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
420 return $ (cs, allCodePathsReturn, mass)
421typeConstraintsForStatement m mass ret (For ident start end inner) = do
422 assignVariable ident (m `M.union` mass)
423 (cs1, n1) <- typeConstraints (m `M.union` mass) start
424 (cs2, n2) <- typeConstraints (m `M.union` mass) end
425 let mass1 = M.insert ident n1 mass
426 (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
427 return $ ((TypeConstraint n1 Number) : (TypeConstraint n2 Number) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
428typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
429 assignVariable ident (m `M.union` mass)
431 (cs1, n1) <- typeConstraints (m `M.union` mass) vals
432 let mass1 = M.insert ident val mass
433 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
434 guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
435 return $ ((TypeConstraint n1 (Array (TUnknown val))) : cs1 ++ cs2, False, mass)
436typeConstraintsForStatement m mass ret (Return val) = do
437 (cs1, n1) <- typeConstraints (m `M.union` mass) val
438 return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
440typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
441typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
442 (cs1, n1) <- typeConstraints m val
443 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
444 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn)
445typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
446 (cs1, n1) <- typeConstraints m val
447 (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
448 (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
449 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
451typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
452typeConstraintsForElseStatement m mass ret (Else elses) = do
453 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
454 return (cs, allCodePathsReturn)
455typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
456 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
457 return (cs, allCodePathsReturn)
459typeConstraintsForAssignmentTarget :: M.Map Ident Int -> M.Map Ident Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
460typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
461 case M.lookup var mass of
462 Nothing -> throwError $ "No local variable with name " ++ show var
464 return [TypeConstraint nval (TUnknown ty)]
465typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
467 (cs1, n1) <- typeConstraints (m `M.union` mass) index
468 cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
469 return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
470typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
473 cs <- typeConstraintsForAssignmentTarget m mass obj tgt
474 return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
476typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
477typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
478typeConstraintsForBlock m mass ret (s:ss) = do
479 (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
481 (True, []) -> return (cs1, True, mass1)
482 (True, _) -> throwError "Unreachable code"
484 (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
485 return (cs1 ++ cs2, b2, mass2)
487solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
488solveTypeConstraints [] s = return s
489solveTypeConstraints all@(TypeConstraint n t:cs) s = do
491 let s' = let (f, g) = runTypeSolution s
492 in TypeSolution (replaceType n t . f, replaceType n t . g)
493 cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
494 solveTypeConstraints cs' s'
495solveTypeConstraints (RowConstraint n r:cs) s = do
497 let s' = let (f, g) = runTypeSolution s
498 in TypeSolution $ (replaceRow n r . f, replaceRow n r . g)
499 cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
500 solveTypeConstraints cs' s'
502substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
503substituteTypeInConstraint n s (TypeConstraint m t)
504 | n == m = unifyTypes s t
505 | otherwise = return [TypeConstraint m (replaceType n s t)]
506substituteTypeInConstraint n s (RowConstraint m r)
507 = return [RowConstraint m (replaceType n s r)]
509substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
510substituteRowInConstraint n r (TypeConstraint m t)
511 = return [TypeConstraint m (replaceRow n r t)]
512substituteRowInConstraint n r (RowConstraint m r1)
513 | m == n = unifyRows r r1
514 | otherwise = return [RowConstraint m (replaceRow n r r1)]
516unifyTypes :: Type -> Type -> Check [TypeConstraint]
517unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
518unifyTypes (TUnknown u) t = do
520 return [TypeConstraint u t]
521unifyTypes t (TUnknown u) = do
523 return [TypeConstraint u t]
524unifyTypes Number Number = return []
525unifyTypes String String = return []
526unifyTypes Boolean Boolean = return []
527unifyTypes (Array s) (Array t) = unifyTypes s t
528unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
529unifyTypes (Function args1 ret1) (Function args2 ret2) = do
530 guardWith "Function applied to incorrect number of args" $ length args1 == length args2
531 cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
532 cs2 <- unifyTypes ret1 ret2
534unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
535unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
536unifyTypes (TypeVar v1) (TypeVar v2) = return []
537unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
538 cs1 <- unifyTypes t1 t3
539 cs2 <- unifyTypes t2 t4
541unifyTypes t1 t2 = throwError $ "Cannot unify " ++ prettyPrintType t1 ++ " with " ++ prettyPrintType t2 ++ "."
543unifyRows :: Row -> Row -> Check [TypeConstraint]
546 (s1, r1') = toList r1
547 (s2, r2') = toList r2
548 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
549 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
550 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
551 in rethrow (\e -> "Cannot unify " ++ prettyPrintRow r1 ++ " with " ++ prettyPrintRow r2 ++ ": " ++ e) $ do
552 cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
553 cs2 <- unifyRows' sd1 r1' sd2 r2'
556 unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
557 unifyRows' [] (RUnknown u) sd r = do
559 return [RowConstraint u (fromList (sd, r))]
560 unifyRows' sd r [] (RUnknown u) = do
562 return [RowConstraint u (fromList (sd, r))]
563 unifyRows' ((name, ty):row) r others (RUnknown u) = do
565 cs <- unifyRows' row r others (RUnknown u')
566 return (RowConstraint u (RCons name ty (RUnknown u')) : cs)
567 unifyRows' [] REmpty [] REmpty = return []
568 unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (fromList (sd1, r1)) ++ " with " ++ prettyPrintRow (fromList (sd2, r2)) ++ "."
569 toList :: Row -> ([(String, Type)], Row)
570 toList (RCons name ty row) = let (tys, rest) = toList row
571 in ((name, ty):tys, rest)
573 fromList :: ([(String, Type)], Row) -> Row
575 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