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 $ desaturateAllTypeSynonyms 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
136replaceTypeVars :: M.Map String Type -> Type -> Type
137replaceTypeVars m = everywhere (mkT replace)
139 replace (TypeVar v) = case M.lookup v m of
144replaceVarsWithUnknowns :: [String] -> Type -> Check Type
145replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)
147 f :: Type -> StateT (M.Map String Int) Check Type
148 f (TypeVar var) | var `elem` idents = do
151 case M.lookup var m of
153 put (M.insert var n m)
155 Just u -> return $ TUnknown u
157 g :: Row -> StateT (M.Map String Int) Check Row
158 g (RowVar var) | var `elem` idents = do
161 case M.lookup var m of
163 put (M.insert var n m)
165 Just u -> return $ RUnknown u
168replaceAllTypeSynonyms :: (D.Data d) => d -> Check d
169replaceAllTypeSynonyms d = do
171 let syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env
172 either throwError return $ saturateAllTypeSynonyms syns d
174desaturateAllTypeSynonyms :: (D.Data d) => d -> d
175desaturateAllTypeSynonyms = everywhere (mkT $ replace)
177 replace (SaturatedTypeSynonym name args) = foldl (\t arg -> TypeApp t arg) (TypeConstructor name) args
180replaceType :: (D.Data d) => Int -> Type -> d -> d
181replaceType n t = everywhere (mkT go)
183 go (TUnknown m) | m == n = t
186replaceRow :: (D.Data d) => Int -> Row -> d -> d
187replaceRow n r = everywhere (mkT go)
189 go (RUnknown m) | m == n = r
192typeOccursCheck :: Int -> Type -> Check ()
193typeOccursCheck u (TUnknown _) = return ()
194typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintType t
196rowOccursCheck :: Int -> Row -> Check ()
197rowOccursCheck u (RUnknown _) = return ()
198rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintRow r
200occursCheck :: (D.Data d) => Int -> d -> Bool
201occursCheck u = everything (||) $ flip extQ g $ mkQ False f
203 f (TUnknown u') | u' == u = True
205 g (RUnknown u') | u' == u = True
208typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
209typeConstraints _ (NumericLiteral _) = do
211 return ([TypeConstraint me Number], me)
212typeConstraints _ (StringLiteral _) = do
214 return ([TypeConstraint me String], me)
215typeConstraints _ (BooleanLiteral _) = do
217 return ([TypeConstraint me Boolean], me)
218typeConstraints m (ArrayLiteral vals) = do
219 all <- mapM (typeConstraints m) vals
220 let (cs, ns) = (concat . map fst &&& map snd) all
222 return (cs ++ map (TypeConstraint me . Array . TUnknown) ns, me)
223typeConstraints m (Unary op val) = do
224 (cs, n1) <- typeConstraints m val
226 return (cs ++ unaryOperatorConstraints op n1 me, me)
227typeConstraints m (Binary op left right) = do
228 (cs1, n1) <- typeConstraints m left
229 (cs2, n2) <- typeConstraints m right
231 return (cs1 ++ cs2 ++ binaryOperatorConstraints op n1 n2 me, me)
232typeConstraints m (ObjectLiteral ps) = do
233 all <- mapM (typeConstraints m . snd) ps
234 let (cs, ns) = (concat . map fst &&& map snd) all
236 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
237 return ((TypeConstraint me (Object (typesToRow tys))) : cs, me)
239 typesToRow [] = REmpty
240 typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
241typeConstraints m (Indexer index val) = do
242 (cs1, n1) <- typeConstraints m index
243 (cs2, n2) <- typeConstraints m val
245 return ((TypeConstraint n1 Number) : (TypeConstraint n2 (Array (TUnknown me))) : cs1 ++ cs2, me)
246typeConstraints m (Accessor prop val) = do
247 (cs, n1) <- typeConstraints m val
250 return ((TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest)))) : cs, me)
251typeConstraints m (Abs args ret) = do
252 ns <- replicateM (length args) fresh
253 let m' = m `M.union` M.fromList (zipWith (,) args ns)
254 (cs, n') <- typeConstraints m' ret
256 return ((TypeConstraint me (Function (map TUnknown ns) (TUnknown n'))) : cs, me)
257typeConstraints m (App f xs) = do
258 (cs1, n1) <- typeConstraints m f
259 all <- mapM (typeConstraints m) xs
260 let (cs2, ns) = (concat . map fst &&& map snd) all
262 return ((TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me))) : cs1 ++ cs2, me)
263typeConstraints m (Var var) =
264 case M.lookup var m of
267 case M.lookup var (names env) of
268 Nothing -> throwError $ show var ++ " is undefined"
269 Just (PolyType idents ty, _) -> do
271 replaced <- replaceVarsWithUnknowns idents ty
272 return ([TypeConstraint me replaced], me)
275 return ([TypeConstraint u (TUnknown me)], me)
276typeConstraints m (Block ss) = do
278 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
279 guardWith "Block is missing a return statement" allCodePathsReturn
281typeConstraints m (Constructor c) = do
283 case M.lookup c (dataConstructors env) of
284 Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"
285 Just (PolyType idents ty) -> do
287 replaced <- replaceVarsWithUnknowns idents ty
288 return ([TypeConstraint me replaced], me)
289typeConstraints m (Case val binders) = do
290 (cs1, n1) <- typeConstraints m val
292 cs2 <- typeConstraintsForBinders m n1 ret binders
293 return (cs1 ++ cs2, ret)
294typeConstraints m (IfThenElse cond th el) = do
295 (cs1, n1) <- typeConstraints m cond
296 (cs2, n2) <- typeConstraints m th
297 (cs3, n3) <- typeConstraints m el
298 return (TypeConstraint n1 Boolean : TypeConstraint n2 (TUnknown n3) : cs1 ++ cs2 ++ cs3, n2)
299typeConstraints m (TypedValue val poly@(PolyType idents ty)) = do
301 guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
302 (cs, n1) <- typeConstraints m val
303 return (TypeConstraint n1 ty : cs, n1)
305unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
306unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
307unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
308unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
310binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
311binaryOperatorConstraints Add = symBinOpConstraints Number
312binaryOperatorConstraints Subtract = symBinOpConstraints Number
313binaryOperatorConstraints Multiply = symBinOpConstraints Number
314binaryOperatorConstraints Divide = symBinOpConstraints Number
315binaryOperatorConstraints Modulus = symBinOpConstraints Number
316binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
317binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
318binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
319binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
320binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
321binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
322binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
323binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
324binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
325binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
326binaryOperatorConstraints EqualTo = equalityBinOpConstraints
327binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
328binaryOperatorConstraints And = symBinOpConstraints Boolean
329binaryOperatorConstraints Or = symBinOpConstraints Boolean
330binaryOperatorConstraints Concat = symBinOpConstraints String
332equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
333equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
335symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
336symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
338asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
339asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
341typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
342typeConstraintsForBinder _ NullBinder = return ([], M.empty)
343typeConstraintsForBinder val (StringBinder _) = constantBinder val String
344typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
345typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
346typeConstraintsForBinder val (VarBinder name) = do
348 return ([TypeConstraint me (TUnknown val)], M.singleton name me)
349typeConstraintsForBinder val (NullaryBinder ctor) = do
351 case M.lookup ctor (dataConstructors env) of
352 Just (PolyType args ret) -> do
353 ret' <- replaceVarsWithUnknowns args ret
354 return ([TypeConstraint val ret'], M.empty)
355 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
356typeConstraintsForBinder val (UnaryBinder ctor binder) = do
358 case M.lookup ctor (dataConstructors env) of
359 Just (PolyType idents f@(Function [_] _)) -> do
361 (Function [ty] ret) <- replaceVarsWithUnknowns idents f
362 (cs, m1) <- typeConstraintsForBinder obj binder
363 return ((TypeConstraint val ret) : (TypeConstraint obj ty) : cs, m1)
364 Just _ -> throwError $ ctor ++ " is not a unary constructor"
365 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
366typeConstraintsForBinder val (ObjectBinder props) = do
369 (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
370 return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
372 typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
373 typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
374 typeConstraintsForProperties nrow row ((name, binder):binders) = do
376 (cs1, m1) <- typeConstraintsForBinder propTy binder
377 (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
378 return (cs1 ++ cs2, M.union m1 m2)
379typeConstraintsForBinder val (ArrayBinder binders rest) = do
381 all <- mapM (typeConstraintsForBinder el) binders
382 let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
383 let arrayConstraint = TypeConstraint val (Array (TUnknown el))
385 Nothing -> return (arrayConstraint : cs1, m1)
387 (cs2, m2) <- typeConstraintsForBinder val binder
388 return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
389typeConstraintsForBinder val (NamedBinder name binder) = do
391 (cs, m) <- typeConstraintsForBinder val binder
392 return (TypeConstraint me (TUnknown val) : cs, M.insert name me m)
393typeConstraintsForBinder val (GuardedBinder cond binder) = do
394 (cs1, m) <- typeConstraintsForBinder val binder
395 (cs2, n) <- typeConstraints m cond
396 return (TypeConstraint n Boolean : cs1 ++ cs2, m)
398constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
399constantBinder val ty = return ([TypeConstraint val ty], M.empty)
401typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
402typeConstraintsForBinders _ _ _ [] = return []
403typeConstraintsForBinders m nval ret ((binder, val):bs) = do
404 (cs1, m1) <- typeConstraintsForBinder nval binder
405 (cs2, n2) <- typeConstraints (M.union m m1) val
406 cs3 <- typeConstraintsForBinders m nval ret bs
407 return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
409assignVariable :: Ident -> M.Map Ident Int -> Check ()
410assignVariable name m =
411 case M.lookup name m of
413 Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
415typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
416typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
417 assignVariable name (m `M.union` mass)
418 (cs1, n1) <- typeConstraints m val
419 return $ (cs1, False, M.insert name n1 mass)
420typeConstraintsForStatement m mass ret (Assignment tgt val) = do
421 (cs1, n1) <- typeConstraints m val
422 cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
423 return (cs1 ++ cs2, False, mass)
424typeConstraintsForStatement m mass ret (While val inner) = do
425 (cs1, n1) <- typeConstraints m val
426 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
427 return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
428typeConstraintsForStatement m mass ret (If ifst) = do
429 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
430 return $ (cs, allCodePathsReturn, mass)
431typeConstraintsForStatement m mass ret (For ident start end inner) = do
432 assignVariable ident (m `M.union` mass)
433 (cs1, n1) <- typeConstraints (m `M.union` mass) start
434 (cs2, n2) <- typeConstraints (m `M.union` mass) end
435 let mass1 = M.insert ident n1 mass
436 (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
437 return $ ((TypeConstraint n1 Number) : (TypeConstraint n2 Number) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
438typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
439 assignVariable ident (m `M.union` mass)
441 (cs1, n1) <- typeConstraints (m `M.union` mass) vals
442 let mass1 = M.insert ident val mass
443 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
444 guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
445 return $ ((TypeConstraint n1 (Array (TUnknown val))) : cs1 ++ cs2, False, mass)
446typeConstraintsForStatement m mass ret (Return val) = do
447 (cs1, n1) <- typeConstraints (m `M.union` mass) val
448 return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
450typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
451typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
452 (cs1, n1) <- typeConstraints m val
453 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
454 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn)
455typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
456 (cs1, n1) <- typeConstraints m val
457 (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
458 (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
459 return ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
461typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
462typeConstraintsForElseStatement m mass ret (Else elses) = do
463 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
464 return (cs, allCodePathsReturn)
465typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
466 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
467 return (cs, allCodePathsReturn)
469typeConstraintsForAssignmentTarget :: M.Map Ident Int -> M.Map Ident Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
470typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
471 case M.lookup var mass of
472 Nothing -> throwError $ "No local variable with name " ++ show var
474 return [TypeConstraint nval (TUnknown ty)]
475typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
477 (cs1, n1) <- typeConstraints (m `M.union` mass) index
478 cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
479 return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
480typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
483 cs <- typeConstraintsForAssignmentTarget m mass obj tgt
484 return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
486typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
487typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
488typeConstraintsForBlock m mass ret (s:ss) = do
489 (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
491 (True, []) -> return (cs1, True, mass1)
492 (True, _) -> throwError "Unreachable code"
494 (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
495 return (cs1 ++ cs2, b2, mass2)
497solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
498solveTypeConstraints [] s = return s
499solveTypeConstraints all@(TypeConstraint n t:cs) s = do
501 let s' = let (f, g) = runTypeSolution s
502 in TypeSolution (replaceType n t . f, replaceType n t . g)
503 cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
504 solveTypeConstraints cs' s'
505solveTypeConstraints (RowConstraint n r:cs) s = do
507 let s' = let (f, g) = runTypeSolution s
508 in TypeSolution $ (replaceRow n r . f, replaceRow n r . g)
509 cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
510 solveTypeConstraints cs' s'
512substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
513substituteTypeInConstraint n s (TypeConstraint m t)
514 | n == m = unifyTypes s t
515 | otherwise = return [TypeConstraint m (replaceType n s t)]
516substituteTypeInConstraint n s (RowConstraint m r)
517 = return [RowConstraint m (replaceType n s r)]
519substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
520substituteRowInConstraint n r (TypeConstraint m t)
521 = return [TypeConstraint m (replaceRow n r t)]
522substituteRowInConstraint n r (RowConstraint m r1)
523 | m == n = unifyRows r r1
524 | otherwise = return [RowConstraint m (replaceRow n r r1)]
526unifyTypes :: Type -> Type -> Check [TypeConstraint]
527unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
528unifyTypes (TUnknown u) t = do
530 return [TypeConstraint u t]
531unifyTypes t (TUnknown u) = do
533 return [TypeConstraint u t]
534unifyTypes (SaturatedTypeSynonym name1 args1) (SaturatedTypeSynonym name2 args2) | name1 == name2 =
535 fmap concat $ zipWithM unifyTypes args1 args2
536unifyTypes (SaturatedTypeSynonym name args) ty = do
538 case M.lookup name (typeSynonyms env) of
539 Just (synArgs, body) -> do
540 let m = M.fromList $ zip synArgs args
541 let replaced = replaceTypeVars m body
542 unifyTypes replaced ty
543 Nothing -> error "Type synonym was not defined"
544unifyTypes ty s@(SaturatedTypeSynonym _ _) = unifyTypes s ty
545unifyTypes Number Number = return []
546unifyTypes String String = return []
547unifyTypes Boolean Boolean = return []
548unifyTypes (Array s) (Array t) = unifyTypes s t
549unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
550unifyTypes (Function args1 ret1) (Function args2 ret2) = do
551 guardWith "Function applied to incorrect number of args" $ length args1 == length args2
552 cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
553 cs2 <- unifyTypes ret1 ret2
555unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
556unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
557unifyTypes (TypeVar v1) (TypeVar v2) = return []
558unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
559 cs1 <- unifyTypes t1 t3
560 cs2 <- unifyTypes t2 t4
562unifyTypes t1 t2 = throwError $ "Cannot unify " ++ prettyPrintType t1 ++ " with " ++ prettyPrintType t2 ++ "."
564unifyRows :: Row -> Row -> Check [TypeConstraint]
567 (s1, r1') = toList r1
568 (s2, r2') = toList r2
569 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
570 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
571 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
572 in rethrow (\e -> "Cannot unify " ++ prettyPrintRow r1 ++ " with " ++ prettyPrintRow r2 ++ ": " ++ e) $ do
573 cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
574 cs2 <- unifyRows' sd1 r1' sd2 r2'
577 unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
578 unifyRows' [] (RUnknown u) sd r = do
580 return [RowConstraint u (fromList (sd, r))]
581 unifyRows' sd r [] (RUnknown u) = do
583 return [RowConstraint u (fromList (sd, r))]
584 unifyRows' ((name, ty):row) r others (RUnknown u) = do
586 cs <- unifyRows' row r others (RUnknown u')
587 return (RowConstraint u (RCons name ty (RUnknown u')) : cs)
588 unifyRows' [] REmpty [] REmpty = return []
589 unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (fromList (sd1, r1)) ++ " with " ++ prettyPrintRow (fromList (sd2, r2)) ++ "."
590 toList :: Row -> ([(String, Type)], Row)
591 toList (RCons name ty row) = let (tys, rest) = toList row
592 in ((name, ty):tys, rest)
594 fromList :: ([(String, Type)], Row) -> Row
596 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