@@ -1,37 +1,62 @@
1module Type.Unify (unify) where
1module Type.Unify (unify) where
3import Control.Applicative ((<|>))
3import Control.Applicative ((<|>))
4−import Control.Monad.State
4+import Control.Monad.Error (ErrorT, throwError, runErrorT)
5+import Control.Monad.State as State
5import qualified Data.List as List
6import qualified Data.List as List
6import qualified Data.Map as Map
7import qualified Data.Map as Map
7import qualified Data.Maybe as Maybe
8import qualified Data.Maybe as Maybe
8import qualified Data.UnionFind.IO as UF
9import qualified Data.UnionFind.IO as UF
10+import Text.PrettyPrint (render)
9import qualified AST.Annotation as A
12import qualified AST.Annotation as A
10import qualified AST.Variable as Var
13import qualified AST.Variable as Var
11import qualified Type.State as TS
14import qualified Type.State as TS
12import Type.Type
15import Type.Type
13import Type.PrettyPrint
16import Type.PrettyPrint
14−import Text.PrettyPrint (render)
17+import qualified Type.Hint as Hint
15import Elm.Utils ((|>))
18import Elm.Utils ((|>))
18unify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
21unify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
19−unify region variable1 variable2 = do
22+unify region variable1 variable2 =
23+ do result <- runErrorT (unifyHelp region variable1 variable2)
24+ either TS.addHint return result
27+-- ACTUALLY UNIFY STUFF
29+type Unify = ErrorT Hint.Hint (StateT TS.SolverState IO)
35+ -> UF.Point Descriptor
36+ -> UF.Point Descriptor
38+typeError region hint t1 t2 =
39+ do msg <- liftIO (Hint.create region hint t1 t2)
43+unifyHelp :: A.Region -> Variable -> Variable -> Unify ()
44+unifyHelp region variable1 variable2 = do
20 equivalent <- liftIO $ UF.equivalent variable1 variable2
45 equivalent <- liftIO $ UF.equivalent variable1 variable2
21 if equivalent
46 if equivalent
22 then return ()
47 then return ()
23 else actuallyUnify region variable1 variable2
48 else actuallyUnify region variable1 variable2
26−actuallyUnify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
51+actuallyUnify :: A.Region -> Variable -> Variable -> Unify ()
27actuallyUnify region variable1 variable2 = do
52actuallyUnify region variable1 variable2 = do
28 desc1 <- liftIO $ UF.descriptor variable1
53 desc1 <- liftIO $ UF.descriptor variable1
29 desc2 <- liftIO $ UF.descriptor variable2
54 desc2 <- liftIO $ UF.descriptor variable2
30− let unify' = unify region
55+ let unifyHelp' = unifyHelp region
32 (name', flex', rank', alias') = combinedDescriptors desc1 desc2
57 (name', flex', rank', alias') = combinedDescriptors desc1 desc2
34− merge1 :: StateT TS.SolverState IO ()
59+ merge1 :: Unify ()
35 merge1 = liftIO $ do
60 merge1 = liftIO $ do
36 if rank desc1 < rank desc2 then UF.union variable2 variable1
61 if rank desc1 < rank desc2 then UF.union variable2 variable1
37 else UF.union variable1 variable2
62 else UF.union variable1 variable2
@@ -42,7 +67,7 @@ actuallyUnify region variable1 variable2 = do
42 , alias = alias'
67 , alias = alias'
45− merge2 :: StateT TS.SolverState IO ()
70+ merge2 :: Unify ()
46 merge2 = liftIO $ do
71 merge2 = liftIO $ do
47 if rank desc1 < rank desc2 then UF.union variable2 variable1
72 if rank desc1 < rank desc2 then UF.union variable2 variable1
48 else UF.union variable1 variable2
73 else UF.union variable1 variable2
@@ -55,7 +80,7 @@ actuallyUnify region variable1 variable2 = do
56 merge = if rank desc1 < rank desc2 then merge1 else merge2
81 merge = if rank desc1 < rank desc2 then merge1 else merge2
58− fresh :: Maybe (Term1 Variable) -> StateT TS.SolverState IO Variable
83+ fresh :: Maybe (Term1 Variable) -> Unify Variable
59 fresh structure = do
84 fresh structure = do
60 v <- liftIO . UF.fresh $ Descriptor
85 v <- liftIO . UF.fresh $ Descriptor
61 { structure = structure
86 { structure = structure
@@ -66,11 +91,11 @@ actuallyUnify region variable1 variable2 = do
66 , mark = noMark
91 , mark = noMark
67 , alias = alias'
92 , alias = alias'
69− TS.register v
94+ lift (TS.register v)
71 flexAndUnify v = do
96 flexAndUnify v = do
72 liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
97 liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
73− unify' variable1 variable2
98+ unifyHelp' variable1 variable2
75 unifyNumber svar (Var.Canonical home name) =
100 unifyNumber svar (Var.Canonical home name) =
76 case home of
101 case home of
@@ -79,17 +104,17 @@ actuallyUnify region variable1 variable2 = do
80 let hint = "Looks like something besides an Int or Float is being used as a number."
105 let hint = "Looks like something besides an Int or Float is being used as a number."
82− TS.addError region (Just hint) variable1 variable2
107+ typeError region (Just hint) variable1 variable2
84 comparableError maybe =
109 comparableError maybe =
85− TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
110+ typeError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
88 "Looks like you want something comparable, but the only valid comparable\n\
113 "Looks like you want something comparable, but the only valid comparable\n\
89 \types are Int, Float, Char, String, lists, or tuples."
114 \types are Int, Float, Char, String, lists, or tuples."
91 appendableError maybe =
116 appendableError maybe =
92− TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
117+ typeError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
95 "Looks like you want something appendable, but the only Strings, Lists,\n\
120 "Looks like you want something appendable, but the only Strings, Lists,\n\
@@ -106,14 +131,14 @@ actuallyUnify region variable1 variable2 = do
106 case struct of
131 case struct of
107 Other -> comparableError Nothing
132 Other -> comparableError Nothing
108 List v -> do flexAndUnify varSuper
133 List v -> do flexAndUnify varSuper
109− unify' v =<< liftIO (variable $ Is Comparable)
134+ unifyHelp' v =<< liftIO (variable $ Is Comparable)
111 | length vs > 6 ->
136 | length vs > 6 ->
112 comparableError $ Just "Cannot compare a tuple with more than 6 elements."
137 comparableError $ Just "Cannot compare a tuple with more than 6 elements."
113 | otherwise ->
138 | otherwise ->
114 do flexAndUnify varSuper
139 do flexAndUnify varSuper
115 cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
140 cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
116− zipWithM_ unify' vs cmpVars
141+ zipWithM_ unifyHelp' vs cmpVars
118 unifyAppendable varSuper varFlex =
143 unifyAppendable varSuper varFlex =
119 do struct <- liftIO $ collectApps varFlex
144 do struct <- liftIO $ collectApps varFlex
@@ -122,7 +147,7 @@ actuallyUnify region variable1 variable2 = do
122 _ -> appendableError Nothing
147 _ -> appendableError Nothing
124 rigidError var =
149 rigidError var =
125− TS.addError region (Just hint) variable1 variable2
150+ typeError region (Just hint) variable1 variable2
128 "Could not unify rigid type variable '" ++ render (pretty Never var) ++ "'.\n" ++
153 "Could not unify rigid type variable '" ++ render (pretty Never var) ++ "'.\n" ++
@@ -153,15 +178,15 @@ actuallyUnify region variable1 variable2 = do
154 (Rigid, _, _, _) -> rigidError variable1
179 (Rigid, _, _, _) -> rigidError variable1
155 (_, Rigid, _, _) -> rigidError variable2
180 (_, Rigid, _, _) -> rigidError variable2
156− _ -> TS.addError region Nothing variable1 variable2
181+ _ -> typeError region Nothing variable1 variable2
158 case (structure desc1, structure desc2) of
183 case (structure desc1, structure desc2) of
159 (Nothing, Nothing) | flex desc1 == Flexible && flex desc1 == Flexible -> merge
184 (Nothing, Nothing) | flex desc1 == Flexible && flex desc1 == Flexible -> merge
160 (Nothing, _) | flex desc1 == Flexible -> merge2
185 (Nothing, _) | flex desc1 == Flexible -> merge2
161 (_, Nothing) | flex desc2 == Flexible -> merge1
186 (_, Nothing) | flex desc2 == Flexible -> merge1
163− (Just (Var1 v), _) -> unify' v variable2
188+ (Just (Var1 v), _) -> unifyHelp' v variable2
164− (_, Just (Var1 v)) -> unify' v variable1
189+ (_, Just (Var1 v)) -> unifyHelp' v variable1
166 (Nothing, _) -> superUnify
191 (Nothing, _) -> superUnify
167 (_, Nothing) -> superUnify
192 (_, Nothing) -> superUnify
@@ -170,33 +195,33 @@ actuallyUnify region variable1 variable2 = do
170 case (type1,type2) of
195 case (type1,type2) of
171 (App1 term1 term2, App1 term1' term2') ->
196 (App1 term1 term2, App1 term1' term2') ->
173− unify' term1 term1'
198+ unifyHelp' term1 term1'
174− unify' term2 term2'
199+ unifyHelp' term2 term2'
175 (Fun1 term1 term2, Fun1 term1' term2') ->
200 (Fun1 term1 term2, Fun1 term1' term2') ->
177− unify' term1 term1'
202+ unifyHelp' term1 term1'
178− unify' term2 term2'
203+ unifyHelp' term2 term2'
180 (EmptyRecord1, EmptyRecord1) ->
205 (EmptyRecord1, EmptyRecord1) ->
181 return ()
206 return ()
183− (Record1 fields ext, EmptyRecord1) | Map.null fields -> unify' ext variable2
208+ (Record1 fields ext, EmptyRecord1) | Map.null fields -> unifyHelp' ext variable2
184− (EmptyRecord1, Record1 fields ext) | Map.null fields -> unify' ext variable1
209+ (EmptyRecord1, Record1 fields ext) | Map.null fields -> unifyHelp' ext variable1
186 (Record1 _ _, Record1 _ _) ->
211 (Record1 _ _, Record1 _ _) ->
187 recordUnify region fresh variable1 variable2
212 recordUnify region fresh variable1 variable2
189− _ -> TS.addError region Nothing variable1 variable2
214+ _ -> typeError region Nothing variable1 variable2
192-- RECORD UNIFICATION
217-- RECORD UNIFICATION
194recordUnify
219recordUnify
195 :: A.Region
220 :: A.Region
196− -> (Maybe (Term1 Variable) -> StateT TS.SolverState IO Variable)
221+ -> (Maybe (Term1 Variable) -> Unify Variable)
197 -> Variable
222 -> Variable
198 -> Variable
223 -> Variable
199− -> StateT TS.SolverState IO ()
224+ -> Unify ()
200recordUnify region fresh variable1 variable2 =
225recordUnify region fresh variable1 variable2 =
201 do (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
226 do (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
202 (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
227 (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
@@ -212,57 +237,57 @@ recordUnify region fresh variable1 variable2 =
212 let addFieldMismatchError missingFields =
237 let addFieldMismatchError missingFields =
213 let msg = fieldMismatchError missingFields
238 let msg = fieldMismatchError missingFields
215− TS.addError region (Just msg) variable1 variable2
240+ typeError region (Just msg) variable1 variable2
217 case (ext1, ext2) of
242 case (ext1, ext2) of
218 (Empty _, Empty _) ->
243 (Empty _, Empty _) ->
219 case Map.null uniqueFields1 && Map.null uniqueFields2 of
244 case Map.null uniqueFields1 && Map.null uniqueFields2 of
220 True -> return ()
245 True -> return ()
221− False -> TS.addError region Nothing variable1 variable2
246+ False -> typeError region Nothing variable1 variable2
223 (Empty var1, Extension var2) ->
248 (Empty var1, Extension var2) ->
224 case (Map.null uniqueFields1, Map.null uniqueFields2) of
249 case (Map.null uniqueFields1, Map.null uniqueFields2) of
225 (_, False) -> addFieldMismatchError uniqueFields2
250 (_, False) -> addFieldMismatchError uniqueFields2
226− (True, True) -> unify region var1 var2
251+ (True, True) -> unifyHelp region var1 var2
227 (False, True) ->
252 (False, True) ->
228 do subRecord <- freshRecord uniqueFields1 var1
253 do subRecord <- freshRecord uniqueFields1 var1
229− unify region subRecord var2
254+ unifyHelp region subRecord var2
231 (Extension var1, Empty var2) ->
256 (Extension var1, Empty var2) ->
232 case (Map.null uniqueFields1, Map.null uniqueFields2) of
257 case (Map.null uniqueFields1, Map.null uniqueFields2) of
233 (False, _) -> addFieldMismatchError uniqueFields1
258 (False, _) -> addFieldMismatchError uniqueFields1
234− (True, True) -> unify region var1 var2
259+ (True, True) -> unifyHelp region var1 var2
235 (True, False) ->
260 (True, False) ->
236 do subRecord <- freshRecord uniqueFields2 var2
261 do subRecord <- freshRecord uniqueFields2 var2
237− unify region var1 subRecord
262+ unifyHelp region var1 subRecord
239 (Extension var1, Extension var2) ->
264 (Extension var1, Extension var2) ->
240 case (Map.null uniqueFields1, Map.null uniqueFields2) of
265 case (Map.null uniqueFields1, Map.null uniqueFields2) of
241 (True, True) ->
266 (True, True) ->
242− unify region var1 var2
267+ unifyHelp region var1 var2
244 (True, False) ->
269 (True, False) ->
245 do subRecord <- freshRecord uniqueFields2 var2
270 do subRecord <- freshRecord uniqueFields2 var2
246− unify region var1 subRecord
271+ unifyHelp region var1 subRecord
248 (False, True) ->
273 (False, True) ->
249 do subRecord <- freshRecord uniqueFields1 var1
274 do subRecord <- freshRecord uniqueFields1 var1
250− unify region subRecord var2
275+ unifyHelp region subRecord var2
252 (False, False) ->
277 (False, False) ->
253 do record1' <- freshRecord uniqueFields1 =<< fresh Nothing
278 do record1' <- freshRecord uniqueFields1 =<< fresh Nothing
254 record2' <- freshRecord uniqueFields2 =<< fresh Nothing
279 record2' <- freshRecord uniqueFields2 =<< fresh Nothing
255− unify region record1' var2
280+ unifyHelp region record1' var2
256− unify region var1 record2'
281+ unifyHelp region var1 record2'
259unifyOverlappingFields
284unifyOverlappingFields
260 :: A.Region
285 :: A.Region
261 -> Map.Map String [Variable]
286 -> Map.Map String [Variable]
262 -> Map.Map String [Variable]
287 -> Map.Map String [Variable]
263− -> StateT TS.SolverState IO ()
288+ -> Unify ()
264unifyOverlappingFields region fields1 fields2 =
289unifyOverlappingFields region fields1 fields2 =
265− Map.intersectionWith (zipWith (unify region)) fields1 fields2
290+ Map.intersectionWith (zipWith (unifyHelp region)) fields1 fields2
266 |> Map.elems
291 |> Map.elems
267 |> concat
292 |> concat
268 |> sequence_
293 |> sequence_