@@ -1,37 +1,62 @@
11module Type.Unify (unify) where
22
33import Control.Applicative ((<|>))
4−import Control.Monad.State
4+import Control.Monad.Error (ErrorT, throwError, runErrorT)
5+import Control.Monad.State as State
56import qualified Data.List as List
67import qualified Data.Map as Map
78import qualified Data.Maybe as Maybe
89import qualified Data.UnionFind.IO as UF
10+import Text.PrettyPrint (render)
11+
912import qualified AST.Annotation as A
1013import qualified AST.Variable as Var
1114import qualified Type.State as TS
1215import Type.Type
1316import Type.PrettyPrint
14−import Text.PrettyPrint (render)
17+import qualified Type.Hint as Hint
1518import Elm.Utils ((|>))
1619
1720
1821unify :: 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
25+
26+
27+-- ACTUALLY UNIFY STUFF
28+
29+type Unify = ErrorT Hint.Hint (StateT TS.SolverState IO)
30+
31+
32+typeError
33+ :: A.Region
34+ -> Maybe String
35+ -> UF.Point Descriptor
36+ -> UF.Point Descriptor
37+ -> Unify a
38+typeError region hint t1 t2 =
39+ do msg <- liftIO (Hint.create region hint t1 t2)
40+ throwError msg
41+
42+
43+unifyHelp :: A.Region -> Variable -> Variable -> Unify ()
44+unifyHelp region variable1 variable2 = do
2045 equivalent <- liftIO $ UF.equivalent variable1 variable2
2146 if equivalent
2247 then return ()
2348 else actuallyUnify region variable1 variable2
2449
2550
26−actuallyUnify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
51+actuallyUnify :: A.Region -> Variable -> Variable -> Unify ()
2752actuallyUnify region variable1 variable2 = do
2853 desc1 <- liftIO $ UF.descriptor variable1
2954 desc2 <- liftIO $ UF.descriptor variable2
30− let unify' = unify region
55+ let unifyHelp' = unifyHelp region
3156
3257 (name', flex', rank', alias') = combinedDescriptors desc1 desc2
3358
34− merge1 :: StateT TS.SolverState IO ()
59+ merge1 :: Unify ()
3560 merge1 = liftIO $ do
3661 if rank desc1 < rank desc2 then UF.union variable2 variable1
3762 else UF.union variable1 variable2
@@ -42,7 +67,7 @@ actuallyUnify region variable1 variable2 = do
4267 , alias = alias'
4368 }
4469
45− merge2 :: StateT TS.SolverState IO ()
70+ merge2 :: Unify ()
4671 merge2 = liftIO $ do
4772 if rank desc1 < rank desc2 then UF.union variable2 variable1
4873 else UF.union variable1 variable2
@@ -55,7 +80,7 @@ actuallyUnify region variable1 variable2 = do
5580
5681 merge = if rank desc1 < rank desc2 then merge1 else merge2
5782
58− fresh :: Maybe (Term1 Variable) -> StateT TS.SolverState IO Variable
83+ fresh :: Maybe (Term1 Variable) -> Unify Variable
5984 fresh structure = do
6085 v <- liftIO . UF.fresh $ Descriptor
6186 { structure = structure
@@ -66,11 +91,11 @@ actuallyUnify region variable1 variable2 = do
6691 , mark = noMark
6792 , alias = alias'
6893 }
69− TS.register v
94+ lift (TS.register v)
7095
7196 flexAndUnify v = do
7297 liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
73− unify' variable1 variable2
98+ unifyHelp' variable1 variable2
7499
75100 unifyNumber svar (Var.Canonical home name) =
76101 case home of
@@ -79,17 +104,17 @@ actuallyUnify region variable1 variable2 = do
79104 _ ->
80105 let hint = "Looks like something besides an Int or Float is being used as a number."
81106 in
82− TS.addError region (Just hint) variable1 variable2
107+ typeError region (Just hint) variable1 variable2
83108
84109 comparableError maybe =
85− TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
110+ typeError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
86111 where
87112 msg =
88113 "Looks like you want something comparable, but the only valid comparable\n\
89114 \types are Int, Float, Char, String, lists, or tuples."
90115
91116 appendableError maybe =
92− TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
117+ typeError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
93118 where
94119 msg =
95120 "Looks like you want something appendable, but the only Strings, Lists,\n\
@@ -106,14 +131,14 @@ actuallyUnify region variable1 variable2 = do
106131 case struct of
107132 Other -> comparableError Nothing
108133 List v -> do flexAndUnify varSuper
109− unify' v =<< liftIO (variable $ Is Comparable)
134+ unifyHelp' v =<< liftIO (variable $ Is Comparable)
110135 Tuple vs
111136 | length vs > 6 ->
112137 comparableError $ Just "Cannot compare a tuple with more than 6 elements."
113138 | otherwise ->
114139 do flexAndUnify varSuper
115140 cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
116− zipWithM_ unify' vs cmpVars
141+ zipWithM_ unifyHelp' vs cmpVars
117142
118143 unifyAppendable varSuper varFlex =
119144 do struct <- liftIO $ collectApps varFlex
@@ -122,7 +147,7 @@ actuallyUnify region variable1 variable2 = do
122147 _ -> appendableError Nothing
123148
124149 rigidError var =
125− TS.addError region (Just hint) variable1 variable2
150+ typeError region (Just hint) variable1 variable2
126151 where
127152 hint =
128153 "Could not unify rigid type variable '" ++ render (pretty Never var) ++ "'.\n" ++
@@ -153,15 +178,15 @@ actuallyUnify region variable1 variable2 = do
153178
154179 (Rigid, _, _, _) -> rigidError variable1
155180 (_, Rigid, _, _) -> rigidError variable2
156− _ -> TS.addError region Nothing variable1 variable2
181+ _ -> typeError region Nothing variable1 variable2
157182
158183 case (structure desc1, structure desc2) of
159184 (Nothing, Nothing) | flex desc1 == Flexible && flex desc1 == Flexible -> merge
160185 (Nothing, _) | flex desc1 == Flexible -> merge2
161186 (_, Nothing) | flex desc2 == Flexible -> merge1
162187
163− (Just (Var1 v), _) -> unify' v variable2
164− (_, Just (Var1 v)) -> unify' v variable1
188+ (Just (Var1 v), _) -> unifyHelp' v variable2
189+ (_, Just (Var1 v)) -> unifyHelp' v variable1
165190
166191 (Nothing, _) -> superUnify
167192 (_, Nothing) -> superUnify
@@ -170,33 +195,33 @@ actuallyUnify region variable1 variable2 = do
170195 case (type1,type2) of
171196 (App1 term1 term2, App1 term1' term2') ->
172197 do merge
173− unify' term1 term1'
174− unify' term2 term2'
198+ unifyHelp' term1 term1'
199+ unifyHelp' term2 term2'
175200 (Fun1 term1 term2, Fun1 term1' term2') ->
176201 do merge
177− unify' term1 term1'
178− unify' term2 term2'
202+ unifyHelp' term1 term1'
203+ unifyHelp' term2 term2'
179204
180205 (EmptyRecord1, EmptyRecord1) ->
181206 return ()
182207
183− (Record1 fields ext, EmptyRecord1) | Map.null fields -> unify' ext variable2
184− (EmptyRecord1, Record1 fields ext) | Map.null fields -> unify' ext variable1
208+ (Record1 fields ext, EmptyRecord1) | Map.null fields -> unifyHelp' ext variable2
209+ (EmptyRecord1, Record1 fields ext) | Map.null fields -> unifyHelp' ext variable1
185210
186211 (Record1 _ _, Record1 _ _) ->
187212 recordUnify region fresh variable1 variable2
188213
189− _ -> TS.addError region Nothing variable1 variable2
214+ _ -> typeError region Nothing variable1 variable2
190215
191216
192217-- RECORD UNIFICATION
193218
194219recordUnify
195220 :: A.Region
196− -> (Maybe (Term1 Variable) -> StateT TS.SolverState IO Variable)
221+ -> (Maybe (Term1 Variable) -> Unify Variable)
197222 -> Variable
198223 -> Variable
199− -> StateT TS.SolverState IO ()
224+ -> Unify ()
200225recordUnify region fresh variable1 variable2 =
201226 do (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
202227 (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
@@ -212,57 +237,57 @@ recordUnify region fresh variable1 variable2 =
212237 let addFieldMismatchError missingFields =
213238 let msg = fieldMismatchError missingFields
214239 in
215− TS.addError region (Just msg) variable1 variable2
240+ typeError region (Just msg) variable1 variable2
216241
217242 case (ext1, ext2) of
218243 (Empty _, Empty _) ->
219244 case Map.null uniqueFields1 && Map.null uniqueFields2 of
220245 True -> return ()
221− False -> TS.addError region Nothing variable1 variable2
246+ False -> typeError region Nothing variable1 variable2
222247
223248 (Empty var1, Extension var2) ->
224249 case (Map.null uniqueFields1, Map.null uniqueFields2) of
225250 (_, False) -> addFieldMismatchError uniqueFields2
226− (True, True) -> unify region var1 var2
251+ (True, True) -> unifyHelp region var1 var2
227252 (False, True) ->
228253 do subRecord <- freshRecord uniqueFields1 var1
229− unify region subRecord var2
254+ unifyHelp region subRecord var2
230255
231256 (Extension var1, Empty var2) ->
232257 case (Map.null uniqueFields1, Map.null uniqueFields2) of
233258 (False, _) -> addFieldMismatchError uniqueFields1
234− (True, True) -> unify region var1 var2
259+ (True, True) -> unifyHelp region var1 var2
235260 (True, False) ->
236261 do subRecord <- freshRecord uniqueFields2 var2
237− unify region var1 subRecord
262+ unifyHelp region var1 subRecord
238263
239264 (Extension var1, Extension var2) ->
240265 case (Map.null uniqueFields1, Map.null uniqueFields2) of
241266 (True, True) ->
242− unify region var1 var2
267+ unifyHelp region var1 var2
243268
244269 (True, False) ->
245270 do subRecord <- freshRecord uniqueFields2 var2
246− unify region var1 subRecord
271+ unifyHelp region var1 subRecord
247272
248273 (False, True) ->
249274 do subRecord <- freshRecord uniqueFields1 var1
250− unify region subRecord var2
275+ unifyHelp region subRecord var2
251276
252277 (False, False) ->
253278 do record1' <- freshRecord uniqueFields1 =<< fresh Nothing
254279 record2' <- freshRecord uniqueFields2 =<< fresh Nothing
255− unify region record1' var2
256− unify region var1 record2'
280+ unifyHelp region record1' var2
281+ unifyHelp region var1 record2'
257282
258283
259284unifyOverlappingFields
260285 :: A.Region
261286 -> Map.Map String [Variable]
262287 -> Map.Map String [Variable]
263− -> StateT TS.SolverState IO ()
288+ -> Unify ()
264289unifyOverlappingFields region fields1 fields2 =
265− Map.intersectionWith (zipWith (unify region)) fields1 fields2
290+ Map.intersectionWith (zipWith (unifyHelp region)) fields1 fields2
266291 |> Map.elems
267292 |> concat
268293 |> sequence_