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 (
27import qualified Data.Data as D
28import Data.Generics (everywhere, everywhereM, everything, mkT, mkM, mkQ, extM, extQ)
30import PureScript.Values
31import PureScript.Types
32import PureScript.Kinds
33import PureScript.Names
34import PureScript.TypeChecker.Monad
35import PureScript.TypeChecker.Kinds
36import PureScript.TypeChecker.Synonyms
37import PureScript.CodeGen.Pretty.Types
38import PureScript.CodeGen.Pretty.Kinds
39import PureScript.CodeGen.Pretty.Values
41import Control.Monad.State
42import Control.Monad.Error
44import Control.Applicative
45import Control.Arrow (Kleisli(..), (***), (&&&), first)
46import qualified Control.Category as C
48import qualified Data.Map as M
50data TypeConstraintOrigin
53 | AssignmentTargetOrigin Ident deriving (Show, D.Data, D.Typeable)
55prettyPrintOrigin :: TypeConstraintOrigin -> String
56prettyPrintOrigin (ValueOrigin val) = prettyPrintValue val
57prettyPrintOrigin (BinderOrigin binder) = prettyPrintBinder binder
58prettyPrintOrigin (AssignmentTargetOrigin ident) = show ident
61 = TypeConstraint Int Type TypeConstraintOrigin
62 | RowConstraint Int Row TypeConstraintOrigin deriving (Show, D.Data, D.Typeable)
64newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }
66emptyTypeSolution :: TypeSolution
67emptyTypeSolution = TypeSolution (TUnknown, RUnknown)
69isFunction :: Value -> Bool
70isFunction (Abs _ _) = True
71isFunction (TypedValue untyped _) = isFunction untyped
74allConstraints :: Ident -> Value -> Check ([TypeConstraint], Int)
75allConstraints name val | isFunction val = do
77 (cs, n) <- typeConstraints (M.singleton name me) val
78 return (TypeConstraint me (TUnknown n) (ValueOrigin val): cs, n)
79allConstraints _ val = typeConstraints M.empty val
81typeOf :: Ident -> Value -> Check PolyType
83 (cs, n) <- allConstraints name val
84 desugared <- replaceAllTypeSynonyms cs
85 solution <- solveTypeConstraints desugared emptyTypeSolution
86 let ty = fst (runTypeSolution solution) n
87 allUnknownsBecameQuantified desugared solution ty
88 return $ varIfUnknown $ desaturateAllTypeSynonyms $ setifyAll ty
90allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
91allUnknownsBecameQuantified cs solution ty = do
93 typesMentioned = findUnknownTypes ty
94 unknownTypes = nub $ flip concatMap cs $ \c -> case c of
95 TypeConstraint u t _ -> u : findUnknownTypes t
96 RowConstraint _ r _ -> findUnknownTypes r
97 unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes
98 guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned
100 rowsMentioned = findUnknownRows ty
101 unknownRows = nub $ flip concatMap cs $ \c -> case c of
102 TypeConstraint _ t _ -> findUnknownRows t
103 RowConstraint u r _ -> u : findUnknownRows r
104 unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
105 guardWith "Unsolved row variable" $ null $ unsolvedRows \\ rowsMentioned
108setify = rowFromList . first (M.toList . M.fromList) . rowToList
110setifyAll :: (D.Data d) => d -> d
111setifyAll = everywhere (mkT setify)
113findUnknownTypes :: (D.Data d) => d -> [Int]
114findUnknownTypes = everything (++) (mkQ [] f)
120findTypeVars :: (D.Data d) => d -> [String]
121findTypeVars = everything (++) (mkQ [] f)
123 f :: Type -> [String]
127findUnknownRows :: (D.Data d) => d -> [Int]
128findUnknownRows = everything (++) (mkQ [] f)
134varIfUnknown :: Type -> PolyType
137 (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty
139 PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'
141 f :: Type -> State (M.Map Int String) Type
146 let name = 't' : show (M.size m)
147 put $ M.insert n name m
148 return $ TypeVar name
149 Just name -> return $ TypeVar name
151 g :: Row -> State (M.Map Int String) Row
156 let name = 'r' : show (M.size m)
157 put $ M.insert n name m
159 Just name -> return $ RowVar name
162replaceTypeVars :: M.Map String Type -> Type -> Type
163replaceTypeVars m = everywhere (mkT replace)
165 replace (TypeVar v) = case M.lookup v m of
170replaceVarsWithUnknowns :: [String] -> Type -> Check Type
171replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)
173 f :: Type -> StateT (M.Map String Int) Check Type
174 f (TypeVar var) | var `elem` idents = do
177 case M.lookup var m of
179 put (M.insert var n m)
181 Just u -> return $ TUnknown u
183 g :: Row -> StateT (M.Map String Int) Check Row
184 g (RowVar var) | var `elem` idents = do
187 case M.lookup var m of
189 put (M.insert var n m)
191 Just u -> return $ RUnknown u
194replaceAllTypeSynonyms :: (D.Data d) => d -> Check d
195replaceAllTypeSynonyms d = do
197 let syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env
198 either throwError return $ saturateAllTypeSynonyms syns d
200desaturateAllTypeSynonyms :: (D.Data d) => d -> d
201desaturateAllTypeSynonyms = everywhere (mkT replace)
203 replace (SaturatedTypeSynonym name args) = foldl TypeApp (TypeConstructor name) args
206replaceType :: (D.Data d) => Int -> Type -> d -> d
207replaceType n t = everywhere (mkT go)
209 go (TUnknown m) | m == n = t
212replaceRow :: (D.Data d) => Int -> Row -> d -> d
213replaceRow n r = everywhere (mkT go)
215 go (RUnknown m) | m == n = r
218typeOccursCheck :: Int -> Type -> Check ()
219typeOccursCheck u (TUnknown _) = return ()
220typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintType t
222rowOccursCheck :: Int -> Row -> Check ()
223rowOccursCheck u (RUnknown _) = return ()
224rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintRow r
226occursCheck :: (D.Data d) => Int -> d -> Bool
227occursCheck u = everything (||) $ flip extQ g $ mkQ False f
229 f (TUnknown u') | u' == u = True
231 g (RUnknown u') | u' == u = True
234typesToRow :: [(String, Type)] -> Row
235typesToRow [] = REmpty
236typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
238rowToList :: Row -> ([(String, Type)], Row)
239rowToList (RCons name ty row) = let (tys, rest) = rowToList row
240 in ((name, ty):tys, rest)
243rowFromList :: ([(String, Type)], Row) -> Row
244rowFromList ([], r) = r
245rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
247ensureNoDuplicateProperties :: [(String, Value)] -> Check ()
248ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps
250typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
251typeConstraints _ v@(NumericLiteral _) = do
253 return ([TypeConstraint me Number (ValueOrigin v)], me)
254typeConstraints _ v@(StringLiteral _) = do
256 return ([TypeConstraint me String (ValueOrigin v)], me)
257typeConstraints _ v@(BooleanLiteral _) = do
259 return ([TypeConstraint me Boolean (ValueOrigin v)], me)
260typeConstraints m v@(ArrayLiteral vals) = do
261 all <- mapM (typeConstraints m) vals
262 let (cs, ns) = (concatMap fst &&& map snd) all
264 return (cs ++ zipWith (\n el -> TypeConstraint me (Array $ TUnknown n) (ValueOrigin el)) ns vals, me)
265typeConstraints m u@(Unary op val) = do
266 (cs, n1) <- typeConstraints m val
268 return (cs ++ unaryOperatorConstraints u op n1 me, me)
269typeConstraints m b@(Binary op left right) = do
270 (cs1, n1) <- typeConstraints m left
271 (cs2, n2) <- typeConstraints m right
273 return (cs1 ++ cs2 ++ binaryOperatorConstraints b op n1 n2 me, me)
274typeConstraints m v@(ObjectLiteral ps) = do
275 ensureNoDuplicateProperties ps
276 all <- mapM (typeConstraints m . snd) ps
277 let (cs, ns) = (concatMap fst &&& map snd) all
279 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
280 return (TypeConstraint me (Object (typesToRow tys)) (ValueOrigin v) : cs, me)
281typeConstraints m v@(ObjectUpdate o ps) = do
282 ensureNoDuplicateProperties ps
283 (cs1, n1) <- typeConstraints m o
284 all <- mapM (typeConstraints m . snd) ps
285 let (cs2, ns) = (concatMap fst &&& map snd) all
287 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
288 return (TypeConstraint n1 (Object (rowFromList (tys, RUnknown row))) (ValueOrigin v) : cs1 ++ cs2, n1)
289typeConstraints m v@(Indexer index val) = do
290 (cs1, n1) <- typeConstraints m index
291 (cs2, n2) <- typeConstraints m val
293 return (TypeConstraint n1 Number (ValueOrigin index) : TypeConstraint n2 (Array (TUnknown me)) (ValueOrigin v) : cs1 ++ cs2, me)
294typeConstraints m v@(Accessor prop val) = do
295 (cs, n1) <- typeConstraints m val
298 return (TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest))) (ValueOrigin v) : cs, me)
299typeConstraints m v@(Abs args ret) = do
300 ns <- replicateM (length args) fresh
301 let m' = m `M.union` M.fromList (zip args ns)
302 (cs, n') <- typeConstraints m' ret
304 return (TypeConstraint me (Function (map TUnknown ns) (TUnknown n')) (ValueOrigin v) : cs, me)
305typeConstraints m v@(App f xs) = do
306 (cs1, n1) <- typeConstraints m f
307 all <- mapM (typeConstraints m) xs
308 let (cs2, ns) = (concatMap fst &&& map snd) all
310 return (TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me)) (ValueOrigin v) : cs1 ++ cs2, me)
311typeConstraints m v@(Var var) =
312 case M.lookup var m of
315 case M.lookup var (names env) of
316 Nothing -> throwError $ show var ++ " is undefined"
317 Just (PolyType idents ty, _) -> do
319 replaced <- replaceVarsWithUnknowns idents ty
320 return ([TypeConstraint me replaced (ValueOrigin v)], me)
323 return ([TypeConstraint u (TUnknown me) (ValueOrigin v)], me)
324typeConstraints m (Block ss) = do
326 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
327 guardWith "Block is missing a return statement" allCodePathsReturn
329typeConstraints m v@(Constructor c) = do
331 case M.lookup c (dataConstructors env) of
332 Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"
333 Just (PolyType idents ty) -> do
335 replaced <- replaceVarsWithUnknowns idents ty
336 return ([TypeConstraint me replaced (ValueOrigin v)], me)
337typeConstraints m (Case val binders) = do
338 (cs1, n1) <- typeConstraints m val
340 cs2 <- typeConstraintsForBinders m n1 ret binders
341 return (cs1 ++ cs2, ret)
342typeConstraints m v@(IfThenElse cond th el) = do
343 (cs1, n1) <- typeConstraints m cond
344 (cs2, n2) <- typeConstraints m th
345 (cs3, n3) <- typeConstraints m el
346 return (TypeConstraint n1 Boolean (ValueOrigin cond) : TypeConstraint n2 (TUnknown n3) (ValueOrigin v) : cs1 ++ cs2 ++ cs3, n2)
347typeConstraints m v@(TypedValue val poly@(PolyType idents ty)) = do
349 guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
350 (cs, n1) <- typeConstraints m val
351 return (TypeConstraint n1 ty (ValueOrigin v) : cs, n1)
353unaryOperatorConstraints :: Value -> UnaryOperator -> Int -> Int -> [TypeConstraint]
354unaryOperatorConstraints v Negate val result = [TypeConstraint val Number (ValueOrigin v), TypeConstraint result Number (ValueOrigin v)]
355unaryOperatorConstraints v Not val result = [TypeConstraint val Boolean (ValueOrigin v), TypeConstraint result Boolean (ValueOrigin v)]
356unaryOperatorConstraints v BitwiseNot val result = [TypeConstraint val Number (ValueOrigin v), TypeConstraint result Number (ValueOrigin v)]
358binaryOperatorConstraints :: Value -> BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
359binaryOperatorConstraints v Add = symBinOpConstraints v Number
360binaryOperatorConstraints v Subtract = symBinOpConstraints v Number
361binaryOperatorConstraints v Multiply = symBinOpConstraints v Number
362binaryOperatorConstraints v Divide = symBinOpConstraints v Number
363binaryOperatorConstraints v Modulus = symBinOpConstraints v Number
364binaryOperatorConstraints v LessThan = asymBinOpConstraints v Number Boolean
365binaryOperatorConstraints v LessThanOrEqualTo = asymBinOpConstraints v Number Boolean
366binaryOperatorConstraints v GreaterThan = asymBinOpConstraints v Number Boolean
367binaryOperatorConstraints v GreaterThanOrEqualTo = asymBinOpConstraints v Number Boolean
368binaryOperatorConstraints v BitwiseAnd = symBinOpConstraints v Number
369binaryOperatorConstraints v BitwiseOr = symBinOpConstraints v Number
370binaryOperatorConstraints v BitwiseXor = symBinOpConstraints v Number
371binaryOperatorConstraints v ShiftLeft = symBinOpConstraints v Number
372binaryOperatorConstraints v ShiftRight = symBinOpConstraints v Number
373binaryOperatorConstraints v ZeroFillShiftRight = symBinOpConstraints v Number
374binaryOperatorConstraints v EqualTo = equalityBinOpConstraints v
375binaryOperatorConstraints v NotEqualTo = equalityBinOpConstraints v
376binaryOperatorConstraints v And = symBinOpConstraints v Boolean
377binaryOperatorConstraints v Or = symBinOpConstraints v Boolean
378binaryOperatorConstraints v Concat = symBinOpConstraints v String
380equalityBinOpConstraints :: Value -> Int -> Int -> Int -> [TypeConstraint]
381equalityBinOpConstraints v left right result = [TypeConstraint left (TUnknown right) (ValueOrigin v), TypeConstraint result Boolean (ValueOrigin v)]
383symBinOpConstraints :: Value -> Type -> Int -> Int -> Int -> [TypeConstraint]
384symBinOpConstraints v ty = asymBinOpConstraints v ty ty
386asymBinOpConstraints :: Value -> Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
387asymBinOpConstraints v ty res left right result = [TypeConstraint left ty (ValueOrigin v), TypeConstraint right ty (ValueOrigin v), TypeConstraint result res (ValueOrigin v)]
389typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
390typeConstraintsForBinder _ NullBinder = return ([], M.empty)
391typeConstraintsForBinder val b@(StringBinder _) = constantBinder b val String
392typeConstraintsForBinder val b@(NumberBinder _) = constantBinder b val Number
393typeConstraintsForBinder val b@(BooleanBinder _) = constantBinder b val Boolean
394typeConstraintsForBinder val b@(VarBinder name) = do
396 return ([TypeConstraint me (TUnknown val) (BinderOrigin b)], M.singleton name me)
397typeConstraintsForBinder val b@(NullaryBinder ctor) = do
399 case M.lookup ctor (dataConstructors env) of
400 Just (PolyType args ret) -> do
401 ret' <- replaceVarsWithUnknowns args ret
402 return ([TypeConstraint val ret' (BinderOrigin b)], M.empty)
403 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
404typeConstraintsForBinder val b@(UnaryBinder ctor binder) = do
406 case M.lookup ctor (dataConstructors env) of
407 Just (PolyType idents f@(Function [_] _)) -> do
409 (Function [ty] ret) <- replaceVarsWithUnknowns idents f
410 (cs, m1) <- typeConstraintsForBinder obj binder
411 return (TypeConstraint val ret (BinderOrigin b) : TypeConstraint obj ty (BinderOrigin b) : cs, m1)
412 Just _ -> throwError $ ctor ++ " is not a unary constructor"
413 _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
414typeConstraintsForBinder val b@(ObjectBinder props) = do
417 (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
418 return (TypeConstraint val (Object (RUnknown row)) (BinderOrigin b) : cs, m1)
420 typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
421 typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row (BinderOrigin b)], M.empty)
422 typeConstraintsForProperties nrow row ((name, binder):binders) = do
424 (cs1, m1) <- typeConstraintsForBinder propTy binder
425 (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
426 return (cs1 ++ cs2, m1 `M.union` m2)
427typeConstraintsForBinder val b@(ArrayBinder binders rest) = do
429 all <- mapM (typeConstraintsForBinder el) binders
430 let (cs1, m1) = (concatMap fst &&& M.unions . map snd) all
431 let arrayConstraint = TypeConstraint val (Array (TUnknown el)) (BinderOrigin b)
433 Nothing -> return (arrayConstraint : cs1, m1)
435 (cs2, m2) <- typeConstraintsForBinder val binder
436 return (arrayConstraint : cs1 ++ cs2, m1 `M.union` m2)
437typeConstraintsForBinder val b@(NamedBinder name binder) = do
439 (cs, m) <- typeConstraintsForBinder val binder
440 return (TypeConstraint me (TUnknown val) (BinderOrigin b) : cs, M.insert name me m)
441typeConstraintsForBinder val b@(GuardedBinder cond binder) = do
442 (cs1, m) <- typeConstraintsForBinder val binder
443 (cs2, n) <- typeConstraints m cond
444 return (TypeConstraint n Boolean (ValueOrigin cond) : cs1 ++ cs2, m)
446constantBinder :: Binder -> Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
447constantBinder b val ty = return ([TypeConstraint val ty (BinderOrigin b)], M.empty)
449typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
450typeConstraintsForBinders _ _ _ [] = return []
451typeConstraintsForBinders m nval ret ((binder, val):bs) = do
452 (cs1, m1) <- typeConstraintsForBinder nval binder
453 (cs2, n2) <- typeConstraints (m `M.union` m1) val
454 cs3 <- typeConstraintsForBinders m nval ret bs
455 return (TypeConstraint n2 (TUnknown ret) (BinderOrigin binder) : cs1 ++ cs2 ++ cs3)
457assignVariable :: Ident -> M.Map Ident Int -> Check ()
458assignVariable name m =
459 case M.lookup name m of
461 Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
463typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
464typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
465 assignVariable name (m `M.union` mass)
466 (cs1, n1) <- typeConstraints m val
467 return (cs1, False, M.insert name n1 mass)
468typeConstraintsForStatement m mass ret (Assignment ident val) = do
469 (cs1, n1) <- typeConstraints m val
470 case M.lookup ident mass of
471 Nothing -> throwError $ "No local variable with name " ++ show ident
473 return (TypeConstraint n1 (TUnknown ty) (AssignmentTargetOrigin ident) : cs1, False, mass)
474typeConstraintsForStatement m mass ret (While val inner) = do
475 (cs1, n1) <- typeConstraints m val
476 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
477 return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2, allCodePathsReturn, mass)
478typeConstraintsForStatement m mass ret (If ifst) = do
479 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
480 return (cs, allCodePathsReturn, mass)
481typeConstraintsForStatement m mass ret (For ident start end inner) = do
482 assignVariable ident (m `M.union` mass)
483 (cs1, n1) <- typeConstraints (m `M.union` mass) start
484 (cs2, n2) <- typeConstraints (m `M.union` mass) end
485 let mass1 = M.insert ident n1 mass
486 (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
487 return (TypeConstraint n1 Number (ValueOrigin start) : TypeConstraint n2 Number (ValueOrigin end) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
488typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
489 assignVariable ident (m `M.union` mass)
491 (cs1, n1) <- typeConstraints (m `M.union` mass) vals
492 let mass1 = M.insert ident val mass
493 (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
494 guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
495 return (TypeConstraint n1 (Array (TUnknown val)) (ValueOrigin vals) : cs1 ++ cs2, False, mass)
496typeConstraintsForStatement m mass ret (Return val) = do
497 (cs1, n1) <- typeConstraints (m `M.union` mass) val
498 return (TypeConstraint n1 (TUnknown ret) (ValueOrigin val) : cs1, True, mass)
500typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
501typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
502 (cs1, n1) <- typeConstraints m val
503 (cs2, _, _) <- typeConstraintsForBlock m mass ret thens
504 return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2, False)
505typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
506 (cs1, n1) <- typeConstraints m val
507 (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
508 (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
509 return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
511typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
512typeConstraintsForElseStatement m mass ret (Else elses) = do
513 (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
514 return (cs, allCodePathsReturn)
515typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
516 (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
517 return (cs, allCodePathsReturn)
519typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
520typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
521typeConstraintsForBlock m mass ret (s:ss) = do
522 (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
524 (True, []) -> return (cs1, True, mass1)
525 (True, _) -> throwError "Unreachable code"
527 (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
528 return (cs1 ++ cs2, b2, mass2)
530solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
531solveTypeConstraints [] s = return s
532solveTypeConstraints all@(TypeConstraint n t o:cs) s = do
533 (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintOrigin o ++ ": " ++ err) $ do
535 let s' = let (f, g) = runTypeSolution s
536 in TypeSolution (replaceType n t . f, replaceType n t . g)
537 cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
539 solveTypeConstraints cs' s'
540solveTypeConstraints (RowConstraint n r o:cs) s = do
541 (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintOrigin o ++ ": " ++ err) $ do
543 let s' = let (f, g) = runTypeSolution s
544 in TypeSolution (replaceRow n r . f, replaceRow n r . g)
545 cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
547 solveTypeConstraints cs' s'
549substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
550substituteTypeInConstraint n s (TypeConstraint m t v)
551 | n == m = unifyTypes v s t
552 | otherwise = return [TypeConstraint m (replaceType n s t) v]
553substituteTypeInConstraint n s (RowConstraint m r v)
554 = return [RowConstraint m (replaceType n s r) v]
556substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
557substituteRowInConstraint n r (TypeConstraint m t v)
558 = return [TypeConstraint m (replaceRow n r t) v]
559substituteRowInConstraint n r (RowConstraint m r1 v)
560 | m == n = unifyRows v r r1
561 | otherwise = return [RowConstraint m (replaceRow n r r1) v]
563unifyTypes :: TypeConstraintOrigin -> Type -> Type -> Check [TypeConstraint]
564unifyTypes _ (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
565unifyTypes o (TUnknown u) t = do
567 return [TypeConstraint u t o]
568unifyTypes o t (TUnknown u) = do
570 return [TypeConstraint u t o]
571unifyTypes o (SaturatedTypeSynonym name1 args1) (SaturatedTypeSynonym name2 args2) | name1 == name2 =
572 fmap concat $ zipWithM (unifyTypes o) args1 args2
573unifyTypes o (SaturatedTypeSynonym name args) ty = do
575 case M.lookup name (typeSynonyms env) of
576 Just (synArgs, body) -> do
577 let m = M.fromList $ zip synArgs args
578 let replaced = replaceTypeVars m body
579 unifyTypes o replaced ty
580 Nothing -> error "Type synonym was not defined"
581unifyTypes o ty s@(SaturatedTypeSynonym _ _) = unifyTypes o s ty
582unifyTypes _ Number Number = return []
583unifyTypes _ String String = return []
584unifyTypes _ Boolean Boolean = return []
585unifyTypes o (Array s) (Array t) = unifyTypes o s t
586unifyTypes o (Object row1) (Object row2) = unifyRows o row1 row2
587unifyTypes o (Function args1 ret1) (Function args2 ret2) = do
588 guardWith "Function applied to incorrect number of args" $ length args1 == length args2
589 cs1 <- fmap concat $ zipWithM (unifyTypes o) args1 args2
590 cs2 <- unifyTypes o ret1 ret2
592unifyTypes _ (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
593unifyTypes _ (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
594unifyTypes o (TypeApp t1 t2) (TypeApp t3 t4) = do
595 cs1 <- unifyTypes o t1 t3
596 cs2 <- unifyTypes o t2 t4
598unifyTypes _ t1 t2 = throwError $ "Cannot unify " ++ prettyPrintType t1 ++ " with " ++ prettyPrintType t2 ++ "."
600unifyRows :: TypeConstraintOrigin -> Row -> Row -> Check [TypeConstraint]
603 (s1, r1') = rowToList r1
604 (s2, r2') = rowToList r2
605 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
606 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
607 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
609 cs1 <- fmap concat $ mapM (uncurry $ unifyTypes o) int
610 cs2 <- unifyRows' o sd1 r1' sd2 r2'
613 unifyRows' :: TypeConstraintOrigin -> [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
614 unifyRows' o [] (RUnknown u) sd r = do
616 return [RowConstraint u (rowFromList (sd, r)) o]
617 unifyRows' o sd r [] (RUnknown u) = do
619 return [RowConstraint u (rowFromList (sd, r)) o]
620 unifyRows' o ns@((name, ty):row) r others (RUnknown u) | not (occursCheck u (ty, row)) = do
622 cs <- unifyRows' o row r others (RUnknown u')
623 return (RowConstraint u (RCons name ty (RUnknown u')) o : cs)
624 unifyRows' _ [] REmpty [] REmpty = return []
625 unifyRows' _ [] (RowVar v1) [] (RowVar v2) | v1 == v2 = return []
626 unifyRows' _ sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (rowFromList (sd1, r1)) ++ " with " ++ prettyPrintRow (rowFromList (sd2, r2)) ++ "."
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