@@ -20,6 +20,8 @@ module PureScript.TypeChecker.Types (
23import Data.List
25import Data.List
24import Data.Function
26import Data.Function
25import qualified Data.Data as D
27import qualified Data.Data as D
@@ -76,7 +78,7 @@ typeOf name val = do
76 solution <- solveTypeConstraints desugared emptyTypeSolution
78 solution <- solveTypeConstraints desugared emptyTypeSolution
77 let ty = fst (runTypeSolution solution) n
79 let ty = fst (runTypeSolution solution) n
78 allUnknownsBecameQuantified desugared solution ty
80 allUnknownsBecameQuantified desugared solution ty
79− return $ varIfUnknown $ desaturateAllTypeSynonyms ty
81+ return $ varIfUnknown $ desaturateAllTypeSynonyms $ setifyAll ty
81allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
83allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
82allUnknownsBecameQuantified cs solution ty = do
84allUnknownsBecameQuantified cs solution ty = do
@@ -95,6 +97,12 @@ allUnknownsBecameQuantified cs solution ty = do
95 unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
97 unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
96 guardWith "Unsolved row variable" $ null $ unsolvedRows \\ rowsMentioned
98 guardWith "Unsolved row variable" $ null $ unsolvedRows \\ rowsMentioned
101+setify = rowFromList . (M.toList . M.fromList *** id) . rowToList
103+setifyAll :: (D.Data d) => d -> d
104+setifyAll = everywhere (mkT setify)
98findUnknownTypes :: (D.Data d) => d -> [Int]
106findUnknownTypes :: (D.Data d) => d -> [Int]
99findUnknownTypes = everything (++) (mkQ [] f)
107findUnknownTypes = everything (++) (mkQ [] f)
@@ -216,6 +224,22 @@ occursCheck u = everything (||) $ flip extQ g $ mkQ False f
216 g (RUnknown u') | u' == u = True
224 g (RUnknown u') | u' == u = True
217 g _ = False
225 g _ = False
227+typesToRow :: [(String, Type)] -> Row
228+typesToRow [] = REmpty
229+typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
231+rowToList :: Row -> ([(String, Type)], Row)
232+rowToList (RCons name ty row) = let (tys, rest) = rowToList row
233+ in ((name, ty):tys, rest)
234+rowToList r = ([], r)
236+rowFromList :: ([(String, Type)], Row) -> Row
237+rowFromList ([], r) = r
238+rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
240+ensureNoDuplicateProperties :: [(String, Value)] -> Check ()
241+ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps
219typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
243typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
220typeConstraints _ v@(NumericLiteral _) = do
244typeConstraints _ v@(NumericLiteral _) = do
221 me <- fresh
245 me <- fresh
@@ -241,14 +265,20 @@ typeConstraints m b@(Binary op left right) = do
241 me <- fresh
265 me <- fresh
242 return (cs1 ++ cs2 ++ binaryOperatorConstraints b op n1 n2 me, me)
266 return (cs1 ++ cs2 ++ binaryOperatorConstraints b op n1 n2 me, me)
243typeConstraints m v@(ObjectLiteral ps) = do
267typeConstraints m v@(ObjectLiteral ps) = do
268+ ensureNoDuplicateProperties ps
244 all <- mapM (typeConstraints m . snd) ps
269 all <- mapM (typeConstraints m . snd) ps
245 let (cs, ns) = (concat . map fst &&& map snd) all
270 let (cs, ns) = (concat . map fst &&& map snd) all
246 me <- fresh
271 me <- fresh
247 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
272 let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
248 return ((TypeConstraint me (Object (typesToRow tys)) (ValueOrigin v)) : cs, me)
273 return ((TypeConstraint me (Object (typesToRow tys)) (ValueOrigin v)) : cs, me)
249− where
274+typeConstraints m v@(ObjectUpdate o ps) = do
250− typesToRow [] = REmpty
275+ ensureNoDuplicateProperties ps
251− typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
276+ (cs1, n1) <- typeConstraints m o
277+ all <- mapM (typeConstraints m . snd) ps
278+ let (cs2, ns) = (concat . map fst &&& map snd) all
280+ let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
281+ return (TypeConstraint n1 (Object (rowFromList (tys, RUnknown row))) (ValueOrigin v) : cs1 ++ cs2, n1)
252typeConstraints m v@(Indexer index val) = do
282typeConstraints m v@(Indexer index val) = do
253 (cs1, n1) <- typeConstraints m index
283 (cs1, n1) <- typeConstraints m index
254 (cs2, n2) <- typeConstraints m val
284 (cs2, n2) <- typeConstraints m val
@@ -563,8 +593,8 @@ unifyTypes _ t1 t2 = throwError $ "Cannot unify " ++ prettyPrintType t1 ++ " wit
563unifyRows :: TypeConstraintOrigin -> Row -> Row -> Check [TypeConstraint]
593unifyRows :: TypeConstraintOrigin -> Row -> Row -> Check [TypeConstraint]
564unifyRows o r1 r2 =
594unifyRows o r1 r2 =
566− (s1, r1') = toList r1
596+ (s1, r1') = rowToList r1
567− (s2, r2') = toList r2
597+ (s2, r2') = rowToList r2
568 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
598 int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
569 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
599 sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
570 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
600 sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
@@ -576,20 +606,14 @@ unifyRows o r1 r2 =
576 unifyRows' :: TypeConstraintOrigin -> [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
606 unifyRows' :: TypeConstraintOrigin -> [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
577 unifyRows' o [] (RUnknown u) sd r = do
607 unifyRows' o [] (RUnknown u) sd r = do
578 rowOccursCheck u r
608 rowOccursCheck u r
579− return [RowConstraint u (fromList (sd, r)) o]
609+ return [RowConstraint u (rowFromList (sd, r)) o]
580 unifyRows' o sd r [] (RUnknown u) = do
610 unifyRows' o sd r [] (RUnknown u) = do
581 rowOccursCheck u r
611 rowOccursCheck u r
582− return [RowConstraint u (fromList (sd, r)) o]
612+ return [RowConstraint u (rowFromList (sd, r)) o]
583− unifyRows' o ((name, ty):row) r others (RUnknown u) = do
613+ unifyRows' o ns@((name, ty):row) r others (RUnknown u) | not (occursCheck u (ty, row)) = do
584 u' <- fresh
614 u' <- fresh
585 cs <- unifyRows' o row r others (RUnknown u')
615 cs <- unifyRows' o row r others (RUnknown u')
586 return (RowConstraint u (RCons name ty (RUnknown u')) o : cs)
616 return (RowConstraint u (RCons name ty (RUnknown u')) o : cs)
587 unifyRows' _ [] REmpty [] REmpty = return []
617 unifyRows' _ [] REmpty [] REmpty = return []
618+ unifyRows' _ [] (RowVar v1) [] (RowVar v2) | v1 == v2 = return []
588− unifyRows' _ sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (fromList (sd1, r1)) ++ " with " ++ prettyPrintRow (fromList (sd2, r2)) ++ "."
619+ unifyRows' _ sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (rowFromList (sd1, r1)) ++ " with " ++ prettyPrintRow (rowFromList (sd2, r2)) ++ "."
589− toList :: Row -> ([(String, Type)], Row)
590− toList (RCons name ty row) = let (tys, rest) = toList row
591− in ((name, ty):tys, rest)
593− fromList :: ([(String, Type)], Row) -> Row
594− fromList ([], r) = r
595− fromList ((name, t):ts, r) = RCons name t (fromList (ts, r))