1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
20import qualified Data.Map as Map
21import qualified Data.Maybe as Maybe
22import Data.Monoid ((<>))
24import qualified AST.Module.Name as ModuleName
25import qualified Data.Bag as Bag
26import qualified Elm.Name as N
27import qualified Reporting.Doc as D
28import qualified Reporting.Render.Type as RT
29import qualified Reporting.Render.Type.Localizer as L
37 = Lambda Type Type [Type]
41 | FlexSuper Super N.Name
43 | RigidSuper Super N.Name
44 | Type ModuleName.Canonical N.Name [Type]
45 | Record (Map.Map N.Name Type) Extension
47 | Tuple Type Type (Maybe Type)
48 | Alias ModuleName.Canonical N.Name [(N.Name, Type)] Type
65iteratedDealias :: Type -> Type
79toDoc :: L.Localizer -> RT.Context -> Type -> D.Doc
80toDoc localizer ctx tipe =
84 (toDoc localizer RT.Func a)
85 (toDoc localizer RT.Func b)
86 (map (toDoc localizer RT.Func) cs)
106 Type home name args ->
108 (L.toDoc localizer home name)
109 (map (toDoc localizer RT.App) args)
112 RT.record (fieldsToDocs localizer fields) (extToDoc ext)
119 (toDoc localizer RT.None a)
120 (toDoc localizer RT.None b)
121 (map (toDoc localizer RT.None) (Maybe.maybeToList maybeC))
123 Alias home name args _ ->
124 aliasToDoc localizer ctx home name args
127aliasToDoc :: L.Localizer -> RT.Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Type)] -> D.Doc
128aliasToDoc localizer ctx home name args =
130 (L.toDoc localizer home name)
131 (map (toDoc localizer RT.App . snd) args)
134fieldsToDocs :: L.Localizer -> Map.Map N.Name Type -> [(D.Doc, D.Doc)]
135fieldsToDocs localizer fields =
136 Map.foldrWithKey (addField localizer) [] fields
139addField :: L.Localizer -> N.Name -> Type -> [(D.Doc, D.Doc)] -> [(D.Doc, D.Doc)]
140addField localizer fieldName fieldType docs =
142 f = D.fromName fieldName
143 t = toDoc localizer RT.None fieldType
148extToDoc :: Extension -> Maybe D.Doc
152 FlexOpen x -> Just (D.fromName x)
153 RigidOpen x -> Just (D.fromName x)
166 | Different (Bag.Bag Problem)
180 | BadFlexSuper Super N.Name Type
181 | BadRigidVar N.Name Type
182 | BadRigidSuper Super N.Name Type
183 | FieldTypo N.Name [N.Name]
184 | FieldsMissing [N.Name]
187instance Functor Diff where
188 fmap func (Diff a b status) =
189 Diff (func a) (func b) status
192instance Applicative Diff where
196 (<*>) (Diff aFunc bFunc status1) (Diff aArg bArg status2) =
197 Diff (aFunc aArg) (bFunc bArg) (merge status1 status2)
200merge :: Status -> Status -> Status
201merge status1 status2 =
206 Different problems1 ->
211 Different problems2 ->
212 Different (Bag.append problems1 problems2)
219toComparison :: L.Localizer -> Type -> Type -> (D.Doc, D.Doc, [Problem])
220toComparison localizer tipe1 tipe2 =
221 case toDiff localizer RT.None tipe1 tipe2 of
222 Diff doc1 doc2 Similar ->
225 Diff doc1 doc2 (Different problems) ->
226 (doc1, doc2, Bag.toList problems)
229toDiff :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
230toDiff localizer ctx tipe1 tipe2 =
231 case (tipe1, tipe2) of
232 (Unit , Unit ) -> same localizer ctx tipe1
233 (Error , Error ) -> same localizer ctx tipe1
234 (Infinite, Infinite) -> same localizer ctx tipe1
236 (FlexVar x, FlexVar y) | x == y -> same localizer ctx tipe1
237 (FlexSuper _ x, FlexSuper _ y) | x == y -> same localizer ctx tipe1
238 (RigidVar x, RigidVar y) | x == y -> same localizer ctx tipe1
239 (RigidSuper _ x, RigidSuper _ y) | x == y -> same localizer ctx tipe1
241 (FlexVar _, _ ) -> similar localizer ctx tipe1 tipe2
242 (_ , FlexVar _) -> similar localizer ctx tipe1 tipe2
244 (FlexSuper s _, t ) | isSuper s t -> similar localizer ctx tipe1 tipe2
245 (t , FlexSuper s _) | isSuper s t -> similar localizer ctx tipe1 tipe2
247 (Lambda a b cs, Lambda x y zs) ->
248 if length cs == length zs then
250 <$> toDiff localizer RT.Func a x
251 <*> toDiff localizer RT.Func b y
252 <*> sequenceA (zipWith (toDiff localizer RT.Func) cs zs)
254 diffLambda localizer ctx a b cs x y zs
256 (Tuple a b Nothing, Tuple x y Nothing) ->
258 <$> toDiff localizer RT.None a x
259 <*> toDiff localizer RT.None b y
262 (Tuple a b (Just c), Tuple x y (Just z)) ->
264 <$> toDiff localizer RT.None a x
265 <*> toDiff localizer RT.None b y
266 <*> ((:[]) <$> toDiff localizer RT.None c z)
268 (Record fields1 ext1, Record fields2 ext2) ->
269 diffRecord localizer fields1 ext1 fields2 ext2
271 (Type home1 name1 args1, Type home2 name2 args2) | home1 == home2 && name1 == name2 ->
272 RT.apply ctx (L.toDoc localizer home1 name1)
273 <$> sequenceA (zipWith (toDiff localizer RT.App) args1 args2)
275 (Alias home1 name1 args1 _, Alias home2 name2 args2 _) | home1 == home2 && name1 == name2 ->
276 RT.apply ctx (L.toDoc localizer home1 name1)
277 <$> sequenceA (zipWith (toDiff localizer RT.App) (map snd args1) (map snd args2))
279 -- start trying to find specific problems
281 (Type home1 name1 args1, Type home2 name2 args2) | L.toString localizer home1 name1 == L.toString localizer home2 name2 ->
283 (nameClashToDoc ctx localizer home1 name1 args1)
284 (nameClashToDoc ctx localizer home2 name2 args2)
287 (Type home name [t1], t2) | isMaybe home name && isSimilar (toDiff localizer ctx t1 t2) ->
289 (RT.apply ctx (D.dullyellow (L.toDoc localizer home name)) [toDoc localizer RT.App t1])
290 (toDoc localizer ctx t2)
291 (Bag.one AnythingFromMaybe)
293 (t1, Type home name [t2]) | isList home name && isSimilar (toDiff localizer ctx t1 t2) ->
295 (toDoc localizer ctx t1)
296 (RT.apply ctx (D.dullyellow (L.toDoc localizer home name)) [toDoc localizer RT.App t2])
297 (Bag.one AnythingToList)
299 (Alias home1 name1 args1 t1, t2) ->
300 case diffAliasedRecord localizer t1 t2 of
301 Just (Diff _ doc2 status) ->
302 Diff (D.dullyellow (aliasToDoc localizer ctx home1 name1 args1)) doc2 status
306 Type home2 name2 args2 | L.toString localizer home1 name1 == L.toString localizer home2 name2 ->
308 (nameClashToDoc ctx localizer home1 name1 (map snd args1))
309 (nameClashToDoc ctx localizer home2 name2 args2)
314 (D.dullyellow (toDoc localizer ctx tipe1))
315 (D.dullyellow (toDoc localizer ctx tipe2))
318 (t1, Alias home2 name2 args2 t2) ->
319 case diffAliasedRecord localizer t1 t2 of
320 Just (Diff doc1 _ status) ->
321 Diff doc1 (D.dullyellow (aliasToDoc localizer ctx home2 name2 args2)) status
325 Type home1 name1 args1 | L.toString localizer home1 name1 == L.toString localizer home2 name2 ->
327 (nameClashToDoc ctx localizer home1 name1 args1)
328 (nameClashToDoc ctx localizer home2 name2 (map snd args2))
333 (D.dullyellow (toDoc localizer ctx tipe1))
334 (D.dullyellow (toDoc localizer ctx tipe2))
339 doc1 = D.dullyellow (toDoc localizer ctx tipe1)
340 doc2 = D.dullyellow (toDoc localizer ctx tipe2)
342 different doc1 doc2 $
344 (RigidVar x, other) -> Bag.one $ BadRigidVar x other
345 (FlexSuper s x, other) -> Bag.one $ BadFlexSuper s x other
346 (RigidSuper s x, other) -> Bag.one $ BadRigidSuper s x other
347 (other, RigidVar x) -> Bag.one $ BadRigidVar x other
348 (other, FlexSuper s x) -> Bag.one $ BadFlexSuper s x other
349 (other, RigidSuper s x) -> Bag.one $ BadRigidSuper s x other
351 (Type home1 name1 [], Type home2 name2 [])
352 | isInt home1 name1 && isFloat home2 name2 -> Bag.one IntFloat
353 | isFloat home1 name1 && isInt home2 name2 -> Bag.one IntFloat
354 | isInt home1 name1 && isString home2 name2 -> Bag.one StringFromInt
355 | isFloat home1 name1 && isString home2 name2 -> Bag.one StringFromFloat
356 | isString home1 name1 && isInt home2 name2 -> Bag.one StringToInt
357 | isString home1 name1 && isFloat home2 name2 -> Bag.one StringToFloat
358 | isBool home2 name2 -> Bag.one AnythingToBool
368same :: L.Localizer -> RT.Context -> Type -> Diff D.Doc
369same localizer ctx tipe =
371 doc = toDoc localizer ctx tipe
376similar :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
377similar localizer ctx t1 t2 =
378 Diff (toDoc localizer ctx t1) (toDoc localizer ctx t2) Similar
381different :: a -> a -> Bag.Bag Problem -> Diff a
382different a b problems =
383 Diff a b (Different problems)
386isSimilar :: Diff a -> Bool
387isSimilar (Diff _ _ status) =
397isBool :: ModuleName.Canonical -> N.Name -> Bool
399 home == ModuleName.basics && name == N.bool
402isInt :: ModuleName.Canonical -> N.Name -> Bool
404 home == ModuleName.basics && name == N.int
407isFloat :: ModuleName.Canonical -> N.Name -> Bool
409 home == ModuleName.basics && name == N.float
412isString :: ModuleName.Canonical -> N.Name -> Bool
414 home == ModuleName.string && name == N.string
417isChar :: ModuleName.Canonical -> N.Name -> Bool
419 home == ModuleName.char && name == N.char
422isMaybe :: ModuleName.Canonical -> N.Name -> Bool
424 home == ModuleName.maybe && name == N.maybe
427isList :: ModuleName.Canonical -> N.Name -> Bool
429 home == ModuleName.list && name == N.list
436isSuper :: Super -> Type -> Bool
438 case iteratedDealias tipe of
441 Number -> isInt h n || isFloat h n
442 Comparable -> isInt h n || isFloat h n || isString h n || isChar h n || isList h n && isSuper super (head args)
443 Appendable -> isString h n || isList h n
444 CompAppend -> isString h n || isList h n && isSuper Comparable (head args)
454nameClashToDoc :: RT.Context -> L.Localizer -> ModuleName.Canonical -> N.Name -> [Type] -> D.Doc
455nameClashToDoc ctx localizer (ModuleName.Canonical _ home) name args =
457 (D.yellow (D.fromName home) <> D.dullyellow ("." <> D.fromName name))
458 (map (toDoc localizer RT.App) args)
462-- DIFF ALIASED RECORD
465diffAliasedRecord :: L.Localizer -> Type -> Type -> Maybe (Diff D.Doc)
466diffAliasedRecord localizer t1 t2 =
467 case (iteratedDealias t1, iteratedDealias t2) of
468 (Record fields1 ext1, Record fields2 ext2) ->
469 Just (diffRecord localizer fields1 ext1 fields2 ext2)
481-- length cs1 /= length cs2
483diffLambda :: L.Localizer -> RT.Context -> Type -> Type -> [Type] -> Type -> Type -> [Type] -> Diff D.Doc
484diffLambda localizer ctx a1 b1 cs1 a2 b2 cs2 =
486 (result1:revArgs1) = reverse (a1:b1:cs1)
487 (result2:revArgs2) = reverse (a2:b2:cs2)
489 numArgs1 = length revArgs1
490 numArgs2 = length revArgs2
492 case toDiff localizer RT.Func result1 result2 of
493 Diff resultDoc1 resultDoc2 Similar ->
494 if numArgs1 < numArgs2 then
495 diffArgMismatch localizer ctx revArgs1 resultDoc1 revArgs2 resultDoc2
498 diffArgMismatch localizer ctx revArgs2 resultDoc2 revArgs1 resultDoc1
500 Diff resultDoc1 resultDoc2 (Different problems) ->
502 (a:b:cs) = reverse (resultDoc1 : map (toDoc localizer RT.Func) revArgs1)
503 (x:y:zs) = reverse (resultDoc2 : map (toDoc localizer RT.Func) revArgs2)
506 (D.dullyellow (RT.lambda ctx a b cs))
507 (D.dullyellow (RT.lambda ctx x y zs))
508 (Bag.append problems (Bag.one ReturnMismatch))
513-- length shortRevArgs >= 2
514-- length longRevArgs >= 2
515-- length shortRevArgs < length longRevArgs
517diffArgMismatch :: L.Localizer -> RT.Context -> [Type] -> D.Doc -> [Type] -> D.Doc -> Diff D.Doc
518diffArgMismatch localizer ctx shortRevArgs shortResult longRevArgs longResult =
521 case toGreedyMatch localizer shortRevArgs longRevArgs of
522 Just (GreedyMatch shortRevArgDocs longRevArgDocs) ->
523 ( reverse (shortResult:shortRevArgDocs)
524 , reverse (longResult:longRevArgDocs)
528 case toGreedyMatch localizer (reverse shortRevArgs) (reverse longRevArgs) of
529 Just (GreedyMatch shortArgDocs longArgDocs) ->
530 ( shortArgDocs ++ [shortResult]
531 , longArgDocs ++ [longResult]
537 D.dullyellow (toDoc localizer RT.Func tipe)
539 ( reverse (shortResult : map toYellowDoc shortRevArgs)
540 , reverse (longResult : map toYellowDoc longRevArgs )
544 (RT.lambda ctx a b cs)
545 (RT.lambda ctx x y zs)
546 (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
554 GreedyMatch [D.Doc] [D.Doc]
559-- length shorterArgs < length longerArgs
561toGreedyMatch :: L.Localizer -> [Type] -> [Type] -> Maybe GreedyMatch
562toGreedyMatch localizer shorterArgs longerArgs =
563 toGreedyMatchHelp localizer shorterArgs longerArgs (GreedyMatch [] [])
566toGreedyMatchHelp :: L.Localizer -> [Type] -> [Type] -> GreedyMatch -> Maybe GreedyMatch
567toGreedyMatchHelp localizer shorterArgs longerArgs match@(GreedyMatch shorterDocs longerDocs) =
570 D.dullyellow (toDoc localizer RT.Func tipe)
572 case (shorterArgs, longerArgs) of
574 case toDiff localizer RT.Func x y of
576 toGreedyMatchHelp localizer xs ys $
577 GreedyMatch (a:shorterDocs) (b:longerDocs)
579 Diff _ _ (Different _) ->
580 toGreedyMatchHelp localizer shorterArgs ys $
581 GreedyMatch shorterDocs (toYellowDoc y : longerDocs)
587 Just (GreedyMatch shorterDocs (map toYellowDoc longerArgs))
597diffRecord :: L.Localizer -> Map.Map N.Name Type -> Extension -> Map.Map N.Name Type -> Extension -> Diff D.Doc
598diffRecord localizer fields1 ext1 fields2 ext2 =
600 toUnknownDocs field tipe =
601 ( D.dullyellow (D.fromName field), toDoc localizer RT.None tipe )
603 toOverlapDocs field t1 t2 =
604 (,) (D.fromName field) <$> toDiff localizer RT.None t1 t2
606 left = Map.mapWithKey toUnknownDocs (Map.difference fields1 fields2)
607 both = Map.intersectionWithKey toOverlapDocs fields1 fields2
608 right = Map.mapWithKey toUnknownDocs (Map.difference fields2 fields1)
612 if Map.null left && Map.null right then
617 <*> Diff left right (Different Bag.empty)
619 (Diff doc1 doc2 status) =
622 <*> extToDiff ext1 ext2
624 Diff doc1 doc2 $ merge status $
625 case (hasFixedFields ext1, hasFixedFields ext2) of
627 case Map.lookupMin left of
628 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
632 else Different $ Bag.one $ FieldsMissing (Map.keys right)
635 case Map.lookupMin left of
636 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
640 case Map.lookupMin right of
641 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields1)
648hasFixedFields :: Extension -> Bool
657-- DIFF RECORD EXTENSION
660extToDiff :: Extension -> Extension -> Diff (Maybe D.Doc)
663 status = extToStatus ext1 ext2
664 extDoc1 = extToDoc ext1
665 extDoc2 = extToDoc ext2
669 Diff extDoc1 extDoc2 status
672 Diff (D.dullyellow <$> extDoc1) (D.dullyellow <$> extDoc2) status
675extToStatus :: Extension -> Extension -> Status
676extToStatus ext1 ext2 =
681 FlexOpen _ -> Similar
682 RigidOpen _ -> Different Bag.empty
689 Closed -> Different Bag.empty
690 FlexOpen _ -> Similar
694 else Different $ Bag.one $ BadRigidVar x (RigidVar y)
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