@@ -5,9 +5,7 @@ module Type.Error
55 , Super(..)
66 , Extension(..)
77 , iteratedDealias
8− , getFields
98 , toDoc
10− , Comparison(..)
119 , Problem(..)
1210 , toComparison
1311 , isInt
@@ -73,19 +71,6 @@ iteratedDealias tipe =
7371 tipe
7472
7573
76−getFields :: Type -> Maybe (Map.Map N.Name Type)
77−getFields tipe =
78− case tipe of
79− Alias _ _ _ real ->
80− getFields real
81−
82− Record fields _ ->
83− Just fields
84−
85− _ ->
86− Nothing
87−
88−
8974
9075-- TO DOC
9176
@@ -128,18 +113,7 @@ toDoc localizer ctx tipe =
128113 (map (toDoc localizer RT.App) args)
129114
130115 Record fields ext ->
131− let
132− entryToDocs (fieldName, fieldType) =
133− ( D.fromName fieldName, toDoc localizer RT.None fieldType )
134−
135− fieldDocs =
136− map entryToDocs (Map.toList fields)
137− in
138− RT.record fieldDocs $
139− case ext of
140− Closed -> Nothing
141− FlexOpen x -> Just (D.fromName x)
142− RigidOpen x -> Just (D.fromName x)
116+ RT.record (fieldsToDocs localizer fields) (extToDoc ext)
143117
144118 Unit ->
145119 "()"
@@ -151,288 +125,251 @@ toDoc localizer ctx tipe =
151125 (map (toDoc localizer RT.None) (Maybe.maybeToList maybeC))
152126
153127 Alias home name args _ ->
154− RT.apply ctx
155− (nameToDoc localizer home name)
156− (map (toDoc localizer RT.App . snd) args)
128+ aliasToDoc localizer ctx home name args
157129
158130
131+aliasToDoc :: L.Localizer -> RT.Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Type)] -> D.Doc
132+aliasToDoc localizer ctx home name args =
133+ RT.apply ctx
134+ (nameToDoc localizer home name)
135+ (map (toDoc localizer RT.App . snd) args)
159136
160−-- DIFF
161137
138+fieldsToDocs :: L.Localizer -> Map.Map N.Name Type -> [(D.Doc, D.Doc)]
139+fieldsToDocs localizer fields =
140+ Map.foldrWithKey (addField localizer) [] fields
162141
163−data Diff
164− = Similar Type Type
165− | DiffLambda Aliases Diff Diff [Diff]
166− | DiffType Aliases ModuleName.Canonical N.Name [Diff]
167− | DiffRecord Aliases [N.Name] (Map.Map N.Name Diff) [N.Name] Extension Extension
168− | DiffTuple Aliases Diff Diff (Maybe Diff)
169− | Clash Type Type
170142
143+addField :: L.Localizer -> N.Name -> Type -> [(D.Doc, D.Doc)] -> [(D.Doc, D.Doc)]
144+addField localizer fieldName fieldType docs =
145+ let
146+ f = D.fromName fieldName
147+ t = toDoc localizer RT.None fieldType
148+ in
149+ (f,t) : docs
171150
172−same :: Type -> Diff
173−same tipe =
174− Similar tipe tipe
175151
152+extToDoc :: Extension -> Maybe D.Doc
153+extToDoc ext =
154+ case ext of
155+ Closed -> Nothing
156+ FlexOpen x -> Just (D.fromName x)
157+ RigidOpen x -> Just (D.fromName x)
176158
177−data Aliases =
178− Aliases
179− { _left :: Maybe N.Name
180− , _right :: Maybe N.Name
181− }
182159
183160
184−{-# NOINLINE noAliases #-}
185−noAliases :: Aliases
186−noAliases =
187− Aliases Nothing Nothing
161+-- DIFF
188162
189163
190−toDiff :: Type -> Type -> Diff
191−toDiff t1 t2 =
192− case (t1, t2) of
193− (Unit , Unit ) -> same t1
194− (Error , Error ) -> same t1
195− (Infinite, Infinite) -> same t1
164+data Diff a =
165+ Diff a a Status
196166
197− (FlexVar x, FlexVar y) | x == y -> same t1
198− (FlexSuper _ x, FlexSuper _ y) | x == y -> same t1
199− (RigidVar x, RigidVar y) | x == y -> same t1
200− (RigidSuper _ x, RigidSuper _ y) | x == y -> same t1
201167
202− (FlexVar _ , _ ) -> Similar t1 t2
203− (_ , FlexVar _ ) -> Similar t1 t2
168+data Status
169+ = Similar
170+ | Different (Bag.Bag Problem)
204171
205− (Lambda a1 b1 cs1, Lambda a2 b2 cs2) | length cs1 == length cs2 ->
206− let
207− a = toDiff a1 a2
208− b = toDiff b1 b2
209− cs = zipWith toDiff cs1 cs2
210− in
211− if isSimilar a && isSimilar b && all isSimilar cs
212− then Similar t1 t2
213− else DiffLambda noAliases a b cs
214172
215− (Tuple a1 b1 Nothing, Tuple a2 b2 Nothing) ->
216− let
217− a = toDiff a1 a2
218− b = toDiff b1 b2
219− in
220− if isSimilar a && isSimilar b
221− then Similar t1 t2
222− else DiffTuple noAliases a b Nothing
173+data Problem
174+ = IntFloat
175+ | StringFromInt
176+ | StringFromFloat
177+ | StringToInt
178+ | StringToFloat
179+ | AnythingToBool
180+ | AnythingFromMaybe
181+ | AnythingToList
182+ | MissingArgs Int
183+ | ReturnMismatch
184+ | BadFlexSuper Super N.Name Type
185+ | BadRigidVar N.Name Type
186+ | BadRigidSuper Super N.Name Type
187+ | FieldTypo N.Name [N.Name]
223188
224− (Tuple a1 b1 (Just c1), Tuple a2 b2 (Just c2)) ->
225− let
226− a = toDiff a1 a2
227− b = toDiff b1 b2
228− c = toDiff c1 c2
229− in
230− if isSimilar a && isSimilar b && isSimilar c
231− then Similar t1 t2
232− else DiffTuple noAliases a b (Just c)
233189
234− (Record fields1 ext1, Record fields2 ext2) ->
235− let
236− left = Map.keys (Map.difference fields1 fields2)
237− both = Map.intersectionWith toDiff fields1 fields2
238− right = Map.keys (Map.difference fields2 fields1)
239− in
240− if null left && null right && all isSimilar both && isExtSimilar ext1 ext2
241− then Similar t1 t2
242− else DiffRecord noAliases left both right ext1 ext2
190+instance Functor Diff where
191+ fmap func (Diff a b status) =
192+ Diff (func a) (func b) status
243193
244− (Type home1 name1 args1, Type home2 name2 args2) | home1 == home2 && name1 == name2 ->
245− let
246− args = zipWith toDiff args1 args2
247− in
248− if all isSimilar args
249− then Similar t1 t2
250− else DiffType noAliases home1 name1 args
251194
252− (Alias home1 name1 args1 _, Alias home2 name2 args2 _) | home1 == home2 && name1 == name2 ->
253− let
254− args = zipWith toDiff (map snd args1) (map snd args2)
255− in
256− if all isSimilar args
257− then Similar t1 t2
258− else DiffType noAliases home1 name1 args
195+instance Applicative Diff where
196+ pure a =
197+ Diff a a Similar
259198
260− (alias@(Alias _ name _ tipe1), tipe2) ->
261− addAlias (const alias) id (\(Aliases _ t) -> Aliases (Just name) t) (toDiff tipe1 tipe2)
199+ (<*>) (Diff aFunc bFunc status1) (Diff aArg bArg status2) =
200+ Diff (aFunc aArg) (bFunc bArg) (merge status1 status2)
262201
263− (tipe1, alias@(Alias _ name _ tipe2)) ->
264− addAlias id (const alias) (\(Aliases t _) -> Aliases t (Just name)) (toDiff tipe1 tipe2)
265202
266− _ ->
267− Clash t1 t2
203+merge :: Status -> Status -> Status
204+merge status1 status2 =
205+ case status1 of
206+ Similar ->
207+ status2
268208
209+ Different problems1 ->
210+ case status2 of
211+ Similar ->
212+ status1
269213
270−isSimilar :: Diff -> Bool
271−isSimilar diff =
272− case diff of
273− Similar _ _ -> True
274− DiffLambda _ _ _ _ -> False
275− DiffType _ _ _ _ -> False
276− DiffRecord _ _ _ _ _ _ -> False
277− DiffTuple _ _ _ _ -> False
278− Clash _ _ -> False
214+ Different problems2 ->
215+ Different (Bag.append problems1 problems2)
279216
280217
281−addAlias :: (Type -> Type) -> (Type -> Type) -> (Aliases -> Aliases) -> Diff -> Diff
282−addAlias updateLeft updateRight updateAliases diff =
283− case diff of
284− Similar t1 t2 ->
285− Similar (updateLeft t1) (updateRight t2)
286218
287− DiffLambda aliases a b cs ->
288− DiffLambda (updateAliases aliases) a b cs
219+-- COMPARISON
289220
290− DiffType aliases home name args ->
291− DiffType (updateAliases aliases) home name args
292221
293− DiffRecord aliases lefts boths rights ext1 ext2 ->
294− DiffRecord (updateAliases aliases) lefts boths rights ext1 ext2
222+toComparison :: L.Localizer -> Type -> Type -> (D.Doc, D.Doc, [Problem])
223+toComparison localizer tipe1 tipe2 =
224+ case toDiff localizer RT.None tipe1 tipe2 of
225+ Diff doc1 doc2 Similar ->
226+ (doc1, doc2, [])
295227
296− DiffTuple aliases a b maybeC ->
297− DiffTuple (updateAliases aliases) a b maybeC
228+ Diff doc1 doc2 (Different problems) ->
229+ (doc1, doc2, Bag.toList problems)
298230
299− Clash t1 t2 ->
300− Clash (updateLeft t1) (updateRight t2)
301231
232+toDiff :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
233+toDiff localizer ctx tipe1 tipe2 =
234+ case (tipe1, tipe2) of
235+ (Unit , Unit ) -> same localizer ctx tipe1
236+ (Error , Error ) -> same localizer ctx tipe1
237+ (Infinite, Infinite) -> same localizer ctx tipe1
302238
239+ (FlexVar x, FlexVar y) | x == y -> same localizer ctx tipe1
240+ (FlexSuper _ x, FlexSuper _ y) | x == y -> same localizer ctx tipe1
241+ (RigidVar x, RigidVar y) | x == y -> same localizer ctx tipe1
242+ (RigidSuper _ x, RigidSuper _ y) | x == y -> same localizer ctx tipe1
303243
304−-- COMPARISON
244+ (FlexVar _, _ ) -> similar localizer ctx tipe1 tipe2
245+ (_ , FlexVar _) -> similar localizer ctx tipe1 tipe2
305246
247+ (Lambda a b cs, Lambda x y zs) ->
248+ if length cs == length zs then
249+ RT.lambda ctx
250+ <$> toDiff localizer RT.Func a x
251+ <*> toDiff localizer RT.Func b y
252+ <*> sequenceA (zipWith (toDiff localizer RT.Func) cs zs)
253+ else
254+ diffLambda localizer ctx a b cs x y zs
306255
307−data Comparison =
308− Comparison
309− { _alias1 :: Maybe N.Name
310− , _type1 :: D.Doc
311− , _alias2 :: Maybe N.Name
312− , _type2 :: D.Doc
313− , _problems :: [Problem]
314− }
256+ (Tuple a b Nothing, Tuple x y Nothing) ->
257+ RT.tuple
258+ <$> toDiff localizer RT.None a x
259+ <*> toDiff localizer RT.None b y
260+ <*> pure []
315261
262+ (Tuple a b (Just c), Tuple x y (Just z)) ->
263+ RT.tuple
264+ <$> toDiff localizer RT.None a x
265+ <*> toDiff localizer RT.None b y
266+ <*> ((:[]) <$> toDiff localizer RT.None c z)
316267
317−data Problem
318− = FieldMismatch [N.Name] [N.Name]
319− | IntFloat
320− | StringFromInt
321− | StringFromFloat
322− | StringToInt
323− | StringToFloat
324− | AnythingToBool
325− | AnythingFromMaybe
326− | AnythingToList
327− | MissingArgs Int
328− | ReturnMismatch
329− | BadFlexSuper Super N.Name Type
330− | BadRigidVar N.Name Type
331− | BadRigidSuper Super N.Name Type
268+ (Record fields1 ext1, Record fields2 ext2) ->
269+ diffRecord localizer fields1 ext1 fields2 ext2
332270
271+ (Type home1 name1 args1, Type home2 name2 args2) | home1 == home2 && name1 == name2 ->
272+ RT.apply ctx (nameToDoc localizer home1 name1)
273+ <$> sequenceA (zipWith (toDiff localizer RT.App) args1 args2)
333274
334−toComparison :: L.Localizer -> Type -> Type -> Comparison
335−toComparison localizer a b =
336− let
337− diff = toDiff a b
338− (Aliases aAlias bAlias) = getAliases diff
339− (Pair aDoc bDoc problems) = diffToPair localizer RT.None diff
340− in
341− Comparison aAlias aDoc bAlias bDoc (Bag.toList problems)
275+ (Alias home1 name1 args1 _, Alias home2 name2 args2 _) | home1 == home2 && name1 == name2 ->
276+ RT.apply ctx (nameToDoc localizer home1 name1)
277+ <$> sequenceA (zipWith (toDiff localizer RT.App) (map snd args1) (map snd args2))
342278
279+ -- start trying to find specific problems
343280
344−getAliases :: Diff -> Aliases
345−getAliases diff =
346− case diff of
347− Similar _ _ -> noAliases
348− DiffLambda aliases _ _ _ -> aliases
349− DiffType aliases _ _ _ -> aliases
350− DiffRecord aliases _ _ _ _ _ -> aliases
351− DiffTuple aliases _ _ _ -> aliases
352− Clash _ _ -> noAliases
281+ (Type home name [t1], t2) | isMaybe home name && isSimilar (toDiff localizer ctx t1 t2) ->
282+ different
283+ (RT.apply ctx (D.dullyellow (nameToDoc localizer home name)) [toDoc localizer RT.App t1])
284+ (toDoc localizer ctx t2)
285+ (Bag.one AnythingFromMaybe)
353286
287+ (t1, Type home name [t2]) | isList home name && isSimilar (toDiff localizer ctx t1 t2) ->
288+ different
289+ (toDoc localizer ctx t1)
290+ (RT.apply ctx (D.dullyellow (nameToDoc localizer home name)) [toDoc localizer RT.App t2])
291+ (Bag.one AnythingToList)
354292
293+ (Alias home name args t1, t2) ->
294+ case diffAliasedRecord localizer t1 t2 of
295+ Just (Diff _ doc2 status) ->
296+ Diff (D.dullyellow (aliasToDoc localizer ctx home name args)) doc2 status
355297
356−-- DIFF TO DOCS
298+ Nothing ->
299+ different
300+ (D.dullyellow (toDoc localizer ctx tipe1))
301+ (D.dullyellow (toDoc localizer ctx tipe2))
302+ Bag.empty
357303
304+ (t1, Alias home name args t2) ->
305+ case diffAliasedRecord localizer t1 t2 of
306+ Just (Diff doc1 _ status) ->
307+ Diff doc1 (D.dullyellow (aliasToDoc localizer ctx home name args)) status
358308
359−data Pair a =
360− Pair a a (Bag.Bag Problem)
309+ Nothing ->
310+ different
311+ (D.dullyellow (toDoc localizer ctx tipe1))
312+ (D.dullyellow (toDoc localizer ctx tipe2))
313+ Bag.empty
361314
315+ pair ->
316+ let
317+ doc1 = D.dullyellow (toDoc localizer ctx tipe1)
318+ doc2 = D.dullyellow (toDoc localizer ctx tipe2)
319+ in
320+ different doc1 doc2 $
321+ case pair of
322+ (RigidVar x, other) -> Bag.one $ BadRigidVar x other
323+ (FlexSuper s x, other) -> Bag.one $ BadFlexSuper s x other
324+ (RigidSuper s x, other) -> Bag.one $ BadRigidSuper s x other
325+ (other, RigidVar x) -> Bag.one $ BadRigidVar x other
326+ (other, FlexSuper s x) -> Bag.one $ BadFlexSuper s x other
327+ (other, RigidSuper s x) -> Bag.one $ BadRigidSuper s x other
362328
363−instance Functor Pair where
364− fmap func (Pair a b ps) =
365− Pair (func a) (func b) ps
329+ (Type home1 name1 [], Type home2 name2 [])
330+ | isInt home1 name1 && isFloat home2 name2 -> Bag.one IntFloat
331+ | isFloat home1 name1 && isInt home2 name2 -> Bag.one IntFloat
332+ | isInt home1 name1 && isString home2 name2 -> Bag.one StringFromInt
333+ | isFloat home1 name1 && isString home2 name2 -> Bag.one StringFromFloat
334+ | isString home1 name1 && isInt home2 name2 -> Bag.one StringToInt
335+ | isString home1 name1 && isFloat home2 name2 -> Bag.one StringToFloat
336+ | isBool home2 name2 -> Bag.one AnythingToBool
366337
338+ (_, _) ->
339+ Bag.empty
367340
368−instance Applicative Pair where
369− pure a =
370− Pair a a Bag.empty
371341
372− (<*>) (Pair aFunc bFunc ps1) (Pair aArg bArg ps2) =
373− Pair (aFunc aArg) (bFunc bArg) (Bag.append ps1 ps2)
374342
343+-- DIFF HELPERS
375344
376−diffToPair :: L.Localizer -> RT.Context -> Diff -> Pair D.Doc
377−diffToPair localizer ctx diff =
378− case diff of
379− Similar tipe1 tipe2 ->
380− Pair (toDoc localizer ctx tipe1) (toDoc localizer ctx tipe2) Bag.empty
381345
382− DiffLambda _ a b cs ->
383− RT.lambda ctx
384− <$> diffToPair localizer RT.Func a
385− <*> diffToPair localizer RT.Func b
386− <*> traverse (diffToPair localizer RT.Func) cs
346+same :: L.Localizer -> RT.Context -> Type -> Diff D.Doc
347+same localizer ctx tipe =
348+ let
349+ doc = toDoc localizer ctx tipe
350+ in
351+ Diff doc doc Similar
387352
388− DiffType _ home name args ->
389− RT.apply ctx (nameToDoc localizer home name)
390− <$> traverse (diffToPair localizer RT.App) args
391353
392− DiffRecord _ left both right ext1 ext2 ->
393− diffRecord localizer left both right ext1 ext2
354+similar :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
355+similar localizer ctx t1 t2 =
356+ Diff (toDoc localizer ctx t1) (toDoc localizer ctx t2) Similar
357+
358+
359+different :: a -> a -> Bag.Bag Problem -> Diff a
360+different a b problems =
361+ Diff a b (Different problems)
362+
363+
364+isSimilar :: Diff a -> Bool
365+isSimilar (Diff _ _ status) =
366+ case status of
367+ Similar -> True
368+ Different _ -> False
394369
395− DiffTuple _ a b maybeC ->
396− RT.tuple
397− <$> diffToPair localizer RT.None a
398− <*> diffToPair localizer RT.None b
399− <*> traverse (diffToPair localizer RT.None) (Maybe.maybeToList maybeC)
400−
401− Clash tipe1 tipe2 ->
402− case (tipe1, tipe2) of
403− (Lambda a b cs, Lambda x y zs) ->
404− diffLambda localizer ctx (a:b:cs) (x:y:zs)
405−
406− (Type home name [t1], t2) | isMaybe home name && isSimilar (toDiff t1 t2) ->
407− Pair (yellowApply localizer ctx home name t1) (toDoc localizer ctx t2) (Bag.one AnythingFromMaybe)
408−
409− (t1, Type home name [t2]) | isList home name && isSimilar (toDiff t1 t2) ->
410− Pair (toDoc localizer ctx t1) (yellowApply localizer ctx home name t2) (Bag.one AnythingToList)
411−
412− pair ->
413− let
414− doc1 = D.dullyellow (toDoc localizer ctx tipe1)
415− doc2 = D.dullyellow (toDoc localizer ctx tipe2)
416− in
417− Pair doc1 doc2 $
418− case pair of
419− (RigidVar x, other) -> Bag.one $ BadRigidVar x other
420− (FlexSuper s x, other) -> Bag.one $ BadFlexSuper s x other
421− (RigidSuper s x, other) -> Bag.one $ BadRigidSuper s x other
422− (other, RigidVar x) -> Bag.one $ BadRigidVar x other
423− (other, FlexSuper s x) -> Bag.one $ BadFlexSuper s x other
424− (other, RigidSuper s x) -> Bag.one $ BadRigidSuper s x other
425−
426− (Type home1 name1 [], Type home2 name2 [])
427− | isInt home1 name1 && isFloat home2 name2 -> Bag.one IntFloat
428− | isFloat home1 name1 && isInt home2 name2 -> Bag.one IntFloat
429− | isInt home1 name1 && isString home2 name2 -> Bag.one StringFromInt
430− | isFloat home1 name1 && isString home2 name2 -> Bag.one StringFromFloat
431− | isString home1 name1 && isInt home2 name2 -> Bag.one StringToInt
432− | isString home1 name1 && isFloat home2 name2 -> Bag.one StringToFloat
433− | isBool home2 name2 -> Bag.one AnythingToBool
434−
435− (_, _) -> Bag.empty
370+
371+
372+-- IS TYPE?
436373
437374
438375isBool :: ModuleName.Canonical -> N.Name -> Bool
@@ -470,11 +407,18 @@ isList home name =
470407 home == ModuleName.list && name == N.list
471408
472409
473−yellowApply :: L.Localizer -> RT.Context -> ModuleName.Canonical -> N.Name -> Type -> D.Doc
474−yellowApply localizer ctx home name tipe =
475− RT.apply ctx
476− (D.dullyellow (nameToDoc localizer home name))
477− [toDoc localizer RT.App tipe]
410+
411+-- DIFF ALIASED RECORD
412+
413+
414+diffAliasedRecord :: L.Localizer -> Type -> Type -> Maybe (Diff D.Doc)
415+diffAliasedRecord localizer t1 t2 =
416+ case (iteratedDealias t1, iteratedDealias t2) of
417+ (Record fields1 ext1, Record fields2 ext2) ->
418+ Just (diffRecord localizer fields1 ext1 fields2 ext2)
419+
420+ _ ->
421+ Nothing
478422
479423
480424
@@ -483,83 +427,72 @@ yellowApply localizer ctx home name tipe =
483427
484428--
485429-- INVARIANTS:
486−-- length types1 >= 2
487−-- length types2 >= 2
488−-- length types1 /= length types2
430+-- length cs1 /= length cs2
489431--
490−diffLambda :: L.Localizer -> RT.Context -> [Type] -> [Type] -> Pair D.Doc
491−diffLambda localizer ctx types1 types2 =
432+diffLambda :: L.Localizer -> RT.Context -> Type -> Type -> [Type] -> Type -> Type -> [Type] -> Diff D.Doc
433+diffLambda localizer ctx a1 b1 cs1 a2 b2 cs2 =
492434 let
493− (result1:revArgs1) = reverse types1
494− (result2:revArgs2) = reverse types2
435+ (result1:revArgs1) = reverse (a1:b1:cs1)
436+ (result2:revArgs2) = reverse (a2:b2:cs2)
495437
496438 numArgs1 = length revArgs1
497439 numArgs2 = length revArgs2
498−
499− diff = toDiff result1 result2
500−
501− (Pair r1 r2 _) = diffToPair localizer RT.Func diff
502440 in
503− if isSimilar diff then
441+ case toDiff localizer RT.Func result1 result2 of
442+ Diff resultDoc1 resultDoc2 Similar ->
443+ if numArgs1 < numArgs2 then
444+ diffArgMismatch localizer ctx revArgs1 resultDoc1 revArgs2 resultDoc2
504445
505− if numArgs1 < numArgs2 then
506− diffArgMismatch localizer ctx revArgs1 r1 revArgs2 r2
507− else
508− diffArgMismatch localizer ctx revArgs2 r2 revArgs1 r1
446+ else
447+ diffArgMismatch localizer ctx revArgs2 resultDoc2 revArgs1 resultDoc1
509448
510− else
511− let
512− (a1:b1:cs1) = reverse (r1 : map (toDoc localizer RT.Func) revArgs1)
513− (a2:b2:cs2) = reverse (r2 : map (toDoc localizer RT.Func) revArgs2)
514− in
515− Pair
516− (D.dullyellow (RT.lambda ctx a1 b1 cs1))
517− (D.dullyellow (RT.lambda ctx a2 b2 cs2))
518− (Bag.one ReturnMismatch)
449+ Diff resultDoc1 resultDoc2 (Different problems) ->
450+ let
451+ (a:b:cs) = reverse (resultDoc1 : map (toDoc localizer RT.Func) revArgs1)
452+ (x:y:zs) = reverse (resultDoc2 : map (toDoc localizer RT.Func) revArgs2)
453+ in
454+ different
455+ (D.dullyellow (RT.lambda ctx a b cs))
456+ (D.dullyellow (RT.lambda ctx x y zs))
457+ (Bag.append problems (Bag.one ReturnMismatch))
519458
520459
521460--
522461-- INVARIANTS:
523462-- length shortRevArgs >= 2
524463-- length longRevArgs >= 2
464+-- length shortRevArgs < length longRevArgs
525465--
526−diffArgMismatch :: L.Localizer -> RT.Context -> [Type] -> D.Doc -> [Type] -> D.Doc -> Pair D.Doc
466+diffArgMismatch :: L.Localizer -> RT.Context -> [Type] -> D.Doc -> [Type] -> D.Doc -> Diff D.Doc
527467diffArgMismatch localizer ctx shortRevArgs shortResult longRevArgs longResult =
528− case toGreedyMatch localizer shortRevArgs longRevArgs of
529− Just (GreedyMatch shortRevArgDocs longRevArgDocs) ->
530− let
531− (a:b:cs) = reverse (shortResult:shortRevArgDocs)
532− (x:y:zs) = reverse (longResult:longRevArgDocs)
533− in
534− Pair
535− (RT.lambda ctx a b cs)
536− (RT.lambda ctx x y zs)
537− (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
538−
539− Nothing ->
540− case toGreedyMatch localizer (reverse shortRevArgs) (reverse longRevArgs) of
541− Just (GreedyMatch shortArgDocs longArgDocs) ->
542− let
543− (a:b:cs) = shortArgDocs ++ [shortResult]
544− (x:y:zs) = longArgDocs ++ [longResult]
545− in
546− Pair
547− (RT.lambda ctx a b cs)
548− (RT.lambda ctx x y zs)
549− (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
468+ let
469+ (a:b:cs, x:y:zs) =
470+ case toGreedyMatch localizer shortRevArgs longRevArgs of
471+ Just (GreedyMatch shortRevArgDocs longRevArgDocs) ->
472+ ( reverse (shortResult:shortRevArgDocs)
473+ , reverse (longResult:longRevArgDocs)
474+ )
550475
551476 Nothing ->
552− let
553− toYellowDoc tipe =
554− D.dullyellow (toDoc localizer RT.Func tipe)
555−
556− (a:b:cs) = reverse (shortResult : map toYellowDoc shortRevArgs)
557− (x:y:zs) = reverse (longResult : map toYellowDoc longRevArgs )
558− in
559− Pair
560− (RT.lambda ctx a b cs)
561− (RT.lambda ctx x y zs)
562− (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
477+ case toGreedyMatch localizer (reverse shortRevArgs) (reverse longRevArgs) of
478+ Just (GreedyMatch shortArgDocs longArgDocs) ->
479+ ( shortArgDocs ++ [shortResult]
480+ , longArgDocs ++ [longResult]
481+ )
482+
483+ Nothing ->
484+ let
485+ toYellowDoc tipe =
486+ D.dullyellow (toDoc localizer RT.Func tipe)
487+ in
488+ ( reverse (shortResult : map toYellowDoc shortRevArgs)
489+ , reverse (longResult : map toYellowDoc longRevArgs )
490+ )
491+ in
492+ different
493+ (RT.lambda ctx a b cs)
494+ (RT.lambda ctx x y zs)
495+ (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
563496
564497
565498
@@ -587,14 +520,12 @@ toGreedyMatchHelp localizer shorterArgs longerArgs match@(GreedyMatch shorterDoc
587520 in
588521 case (shorterArgs, longerArgs) of
589522 (x:xs, y:ys) ->
590− case toDiff x y of
591− Similar a b ->
523+ case toDiff localizer RT.Func x y of
524+ Diff a b Similar ->
592525 toGreedyMatchHelp localizer xs ys $
593− GreedyMatch
594− (toDoc localizer RT.Func a : shorterDocs)
595− (toDoc localizer RT.Func b : longerDocs)
526+ GreedyMatch (a:shorterDocs) (b:longerDocs)
596527
597− _ ->
528+ Diff _ _ (Different _) ->
598529 toGreedyMatchHelp localizer shorterArgs ys $
599530 GreedyMatch shorterDocs (toYellowDoc y : longerDocs)
600531
@@ -612,165 +543,104 @@ toGreedyMatchHelp localizer shorterArgs longerArgs match@(GreedyMatch shorterDoc
612543-- RECORD DIFFS
613544
614545
615−diffRecord
616− :: L.Localizer
617− -> [N.Name]
618− -> Map.Map N.Name Diff
619− -> [N.Name]
620− -> Extension
621− -> Extension
622− -> Pair D.Doc
623−diffRecord localizer only1 both only2 ext1 ext2 =
624− if null only1 && null only2 then
625− case findBadOverlaps localizer both of
626− [] ->
627− case diffExt ext1 ext2 of
628− ExtSimilar ->
629− Pair
630− (toBoringRecord (Map.size both) ext1)
631− (toBoringRecord (Map.size both) ext2)
632− Bag.empty
633−
634− ExtDifferent maybeExt1 maybeExt2 problems ->
635− Pair
636− (RT.record [] (fmap (D.dullyellow . D.fromName) maybeExt1))
637− (RT.record [] (fmap (D.dullyellow . D.fromName) maybeExt2))
638− problems
639−
640− overlaps@(bad:bads) ->
641− if length overlaps < Map.size both then
642− Pair
643− (RT.recordSnippet (toOverlapDoc _doc1 bad) (map (toOverlapDoc _doc1) bads))
644− (RT.recordSnippet (toOverlapDoc _doc2 bad) (map (toOverlapDoc _doc2) bads))
645− (foldr Bag.append Bag.empty (map _problemBag overlaps))
646− else
647− Pair
648− (toOverlapRecord _doc1 bad bads ext1)
649− (toOverlapRecord _doc2 bad bads ext2)
650− (foldr Bag.append Bag.empty (map _problemBag overlaps))
651−
652− else
653− Pair
654− (toMissingDoc (Map.size both) only1 ext1)
655− (toMissingDoc (Map.size both) only2 ext2)
656− (Bag.one (FieldMismatch only1 only2))
657−
658−
659−toOverlapDoc :: (BadOverlap -> D.Doc) -> BadOverlap -> (D.Doc, D.Doc)
660−toOverlapDoc getDoc overlap@(BadOverlap field _ _ _) =
661− (D.fromName field, getDoc overlap)
662−
663−
664−toOverlapRecord :: (BadOverlap -> D.Doc) -> BadOverlap -> [BadOverlap] -> Extension -> D.Doc
665−toOverlapRecord getDoc bad bads ext =
666− let go = toOverlapDoc getDoc in
667− case ext of
668− Closed -> RT.record (map go (bad:bads)) Nothing
669− FlexOpen _ -> RT.recordSnippet (go bad) (map go bads)
670− RigidOpen _ -> RT.recordSnippet (go bad) (map go bads)
671−
672−
673−toMissingDoc :: Int -> [N.Name] -> Extension -> D.Doc
674−toMissingDoc numSharedFields uniqueFields ext =
675− case map emphasizeFieldName uniqueFields of
676− [] ->
677− toBoringRecord numSharedFields ext
678−
679− doc:docs ->
680− if length uniqueFields < numSharedFields then
681− RT.recordSnippet doc docs
682− else
683− case ext of
684− Closed -> RT.record (doc:docs) Nothing
685− FlexOpen _ -> RT.recordSnippet doc docs
686− RigidOpen _ -> RT.recordSnippet doc docs
687−
546+diffRecord :: L.Localizer -> Map.Map N.Name Type -> Extension -> Map.Map N.Name Type -> Extension -> Diff D.Doc
547+diffRecord localizer fields1 ext1 fields2 ext2 =
548+ let
549+ toUnknownDocs field tipe =
550+ ( D.dullyellow (D.fromName field), toDoc localizer RT.None tipe )
688551
689−emphasizeFieldName :: N.Name -> (D.Doc, D.Doc)
690−emphasizeFieldName field =
691− ( D.dullyellow (D.fromName field), "..." )
552+ toOverlapDocs field t1 t2 =
553+ (,) (D.fromName field) <$> toDiff localizer RT.None t1 t2
692554
555+ left = Map.mapWithKey toUnknownDocs (Map.difference fields1 fields2)
556+ both = Map.intersectionWithKey toOverlapDocs fields1 fields2
557+ right = Map.mapWithKey toUnknownDocs (Map.difference fields2 fields1)
693558
694−toBoringRecord :: Int -> Extension -> D.Doc
695−toBoringRecord numFields ext =
559+ fieldsDiff =
560+ Map.elems <$>
561+ if Map.null left && Map.null right then
562+ sequenceA both
563+ else
564+ Map.union
565+ <$> sequenceA both
566+ <*> Diff left right (Different Bag.empty)
567+
568+ (Diff doc1 doc2 status) =
569+ RT.record
570+ <$> fieldsDiff
571+ <*> extToDiff ext1 ext2
572+ in
573+ Diff doc1 doc2 $ merge status $
574+ case (hasFixedFields ext1, hasFixedFields ext2) of
575+ (True, True) ->
576+ case Map.lookupMin left of
577+ Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
578+ Nothing ->
579+ case Map.lookupMin right of
580+ Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields1)
581+ Nothing -> Similar
582+
583+ (False, True) ->
584+ case Map.lookupMin left of
585+ Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
586+ Nothing -> Similar
587+
588+ (True, False) ->
589+ case Map.lookupMin right of
590+ Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields1)
591+ Nothing -> Similar
592+
593+ (False, False) ->
594+ Similar
595+
596+
597+hasFixedFields :: Extension -> Bool
598+hasFixedFields ext =
696599 case ext of
697− Closed -> if numFields == 0 then "{}" else "{ ... }"
698− FlexOpen _ -> "{ ... }"
699− RigidOpen _ -> "{ ... }"
600+ Closed -> True
601+ FlexOpen _ -> False
602+ RigidOpen _ -> True
700603
701604
702605
703606-- DIFF RECORD EXTENSION
704607
705608
706−isExtSimilar :: Extension -> Extension -> Bool
707−isExtSimilar ext1 ext2 =
708− case diffExt ext1 ext2 of
709− ExtSimilar ->
710− True
711−
712− ExtDifferent _ _ _ ->
713− False
714−
609+extToDiff :: Extension -> Extension -> Diff (Maybe D.Doc)
610+extToDiff ext1 ext2 =
611+ let
612+ status = extToStatus ext1 ext2
613+ extDoc1 = extToDoc ext1
614+ extDoc2 = extToDoc ext2
615+ in
616+ case status of
617+ Similar ->
618+ Diff extDoc1 extDoc2 status
715619
716−data ExtDiff
717− = ExtSimilar
718− | ExtDifferent (Maybe N.Name) (Maybe N.Name) (Bag.Bag Problem)
620+ Different _ ->
621+ Diff (D.dullyellow <$> extDoc1) (D.dullyellow <$> extDoc2) status
719622
720623
721−diffExt :: Extension -> Extension -> ExtDiff
722−diffExt ext1 ext2 =
723− let
724− different x y = ExtDifferent x y Bag.empty
725− in
624+extToStatus :: Extension -> Extension -> Status
625+extToStatus ext1 ext2 =
726626 case ext1 of
727627 Closed ->
728628 case ext2 of
729− Closed -> ExtSimilar
730− FlexOpen y -> different Nothing (Just y)
731− RigidOpen y -> different Nothing (Just y)
629+ Closed -> Similar
630+ FlexOpen _ -> Different Bag.empty
631+ RigidOpen _ -> Different Bag.empty
732632
733− FlexOpen x ->
633+ FlexOpen _ ->
734634 case ext2 of
735− Closed -> different (Just x) Nothing
736− FlexOpen _ -> ExtSimilar
737− RigidOpen _ -> ExtSimilar
635+ Closed -> Different Bag.empty
636+ FlexOpen _ -> Similar
637+ RigidOpen _ -> Similar
738638
739639 RigidOpen x ->
740640 case ext2 of
741− Closed -> different (Just x) Nothing
742− FlexOpen _ -> ExtSimilar
641+ Closed -> Different Bag.empty
642+ FlexOpen _ -> Similar
743643 RigidOpen y ->
744− if x == y then
745− ExtSimilar
746− else
747− ExtDifferent (Just x) (Just y) (Bag.one (BadRigidVar x (RigidVar y)))
748−
749−
750−
751−-- BAD OVERLAP
752−
753−
754−data BadOverlap =
755− BadOverlap
756− { _field :: N.Name
757− , _doc1 :: D.Doc
758− , _doc2 :: D.Doc
759− , _problemBag :: Bag.Bag Problem
760− }
761−
762−
763−findBadOverlaps :: L.Localizer -> Map.Map N.Name Diff -> [BadOverlap]
764−findBadOverlaps localizer overlaps =
765− Map.foldrWithKey (addBadOverlap localizer) [] overlaps
766−
767−
768−addBadOverlap :: L.Localizer -> N.Name -> Diff -> [BadOverlap] -> [BadOverlap]
769−addBadOverlap localizer field diff badOverlaps =
770− if isSimilar diff then
771− badOverlaps
772− else
773− let
774− (Pair aDoc bDoc problems) = diffToPair localizer RT.None diff
775− in
776− BadOverlap field aDoc bDoc problems : badOverlaps
644+ if x == y
645+ then Similar
646+ else Different $ Bag.one $ BadRigidVar x (RigidVar y)