1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
22import qualified Data.Map as Map
23import qualified Data.Maybe as Maybe
25import qualified AST.Module.Name as ModuleName
26import qualified Data.Bag as Bag
27import qualified Elm.Name as N
28import qualified Reporting.Doc as D
29import qualified Reporting.Render.Type as RT
30import qualified Reporting.Render.Type.Localizer as L
38 = Lambda Type Type [Type]
42 | FlexSuper Super N.Name
44 | RigidSuper Super N.Name
45 | Type ModuleName.Canonical N.Name [Type]
46 | Record (Map.Map N.Name Type) Extension
48 | Tuple Type Type (Maybe Type)
49 | Alias ModuleName.Canonical N.Name [(N.Name, Type)] Type
66iteratedDealias :: Type -> Type
76getFields :: Type -> Maybe (Map.Map N.Name Type)
93nameToDoc :: L.Localizer -> ModuleName.Canonical -> N.Name -> D.Doc
94nameToDoc localizer (ModuleName.Canonical _ home) name =
95 L.toDoc localizer home name
98toDoc :: L.Localizer -> RT.Context -> Type -> D.Doc
99toDoc localizer ctx tipe =
103 (toDoc localizer RT.Func a)
104 (toDoc localizer RT.Func b)
105 (map (toDoc localizer RT.Func) cs)
125 Type home name args ->
127 (nameToDoc localizer home name)
128 (map (toDoc localizer RT.App) args)
132 entryToDocs (fieldName, fieldType) =
133 ( D.fromName fieldName, toDoc localizer RT.None fieldType )
136 map entryToDocs (Map.toList fields)
138 RT.record fieldDocs $
141 FlexOpen x -> Just (D.fromName x)
142 RigidOpen x -> Just (D.fromName x)
149 (toDoc localizer RT.None a)
150 (toDoc localizer RT.None b)
151 (map (toDoc localizer RT.None) (Maybe.maybeToList maybeC))
153 Alias home name args _ ->
155 (nameToDoc localizer home name)
156 (map (toDoc localizer RT.App . snd) args)
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)
179 { _left :: Maybe N.Name
180 , _right :: Maybe N.Name
184{-# NOINLINE noAliases #-}
187 Aliases Nothing Nothing
190toDiff :: Type -> Type -> Diff
193 (Unit , Unit ) -> same t1
194 (Error , Error ) -> same t1
195 (Infinite, Infinite) -> same t1
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
202 (FlexVar _ , _ ) -> Similar t1 t2
203 (_ , FlexVar _ ) -> Similar t1 t2
205 (Lambda a1 b1 cs1, Lambda a2 b2 cs2) | length cs1 == length cs2 ->
209 cs = zipWith toDiff cs1 cs2
211 if isSimilar a && isSimilar b && all isSimilar cs
213 else DiffLambda noAliases a b cs
215 (Tuple a1 b1 Nothing, Tuple a2 b2 Nothing) ->
220 if isSimilar a && isSimilar b
222 else DiffTuple noAliases a b Nothing
224 (Tuple a1 b1 (Just c1), Tuple a2 b2 (Just c2)) ->
230 if isSimilar a && isSimilar b && isSimilar c
232 else DiffTuple noAliases a b (Just c)
234 (Record fields1 ext1, Record fields2 ext2) ->
236 left = Map.keys (Map.difference fields1 fields2)
237 both = Map.intersectionWith toDiff fields1 fields2
238 right = Map.keys (Map.difference fields2 fields1)
240 if null left && null right && all isSimilar both && isExtSimilar ext1 ext2
242 else DiffRecord noAliases left both right ext1 ext2
244 (Type home1 name1 args1, Type home2 name2 args2) | home1 == home2 && name1 == name2 ->
246 args = zipWith toDiff args1 args2
248 if all isSimilar args
250 else DiffType noAliases home1 name1 args
252 (Alias home1 name1 args1 _, Alias home2 name2 args2 _) | home1 == home2 && name1 == name2 ->
254 args = zipWith toDiff (map snd args1) (map snd args2)
256 if all isSimilar args
258 else DiffType noAliases home1 name1 args
260 (alias@(Alias _ name _ tipe1), tipe2) ->
261 addAlias (const alias) id (\(Aliases _ t) -> Aliases (Just name) t) (toDiff tipe1 tipe2)
263 (tipe1, alias@(Alias _ name _ tipe2)) ->
264 addAlias id (const alias) (\(Aliases t _) -> Aliases t (Just name)) (toDiff tipe1 tipe2)
270isSimilar :: Diff -> Bool
274 DiffLambda _ _ _ _ -> False
275 DiffType _ _ _ _ -> False
276 DiffRecord _ _ _ _ _ _ -> False
277 DiffTuple _ _ _ _ -> False
281addAlias :: (Type -> Type) -> (Type -> Type) -> (Aliases -> Aliases) -> Diff -> Diff
282addAlias updateLeft updateRight updateAliases diff =
285 Similar (updateLeft t1) (updateRight t2)
287 DiffLambda aliases a b cs ->
288 DiffLambda (updateAliases aliases) a b cs
290 DiffType aliases home name args ->
291 DiffType (updateAliases aliases) home name args
293 DiffRecord aliases lefts boths rights ext1 ext2 ->
294 DiffRecord (updateAliases aliases) lefts boths rights ext1 ext2
296 DiffTuple aliases a b maybeC ->
297 DiffTuple (updateAliases aliases) a b maybeC
300 Clash (updateLeft t1) (updateRight t2)
309 { _alias1 :: Maybe N.Name
311 , _alias2 :: Maybe N.Name
313 , _problems :: [Problem]
318 = FieldMismatch [N.Name] [N.Name]
329 | BadFlexSuper Super N.Name Type
330 | BadRigidVar N.Name Type
331 | BadRigidSuper Super N.Name Type
334toComparison :: L.Localizer -> Type -> Type -> Comparison
335toComparison localizer a b =
338 (Aliases aAlias bAlias) = getAliases diff
339 (Pair aDoc bDoc problems) = diffToPair localizer RT.None diff
341 Comparison aAlias aDoc bAlias bDoc (Bag.toList problems)
344getAliases :: Diff -> Aliases
347 Similar _ _ -> noAliases
348 DiffLambda aliases _ _ _ -> aliases
349 DiffType aliases _ _ _ -> aliases
350 DiffRecord aliases _ _ _ _ _ -> aliases
351 DiffTuple aliases _ _ _ -> aliases
352 Clash _ _ -> noAliases
360 Pair a a (Bag.Bag Problem)
363instance Functor Pair where
364 fmap func (Pair a b ps) =
365 Pair (func a) (func b) ps
368instance Applicative Pair where
372 (<*>) (Pair aFunc bFunc ps1) (Pair aArg bArg ps2) =
373 Pair (aFunc aArg) (bFunc bArg) (Bag.append ps1 ps2)
376diffToPair :: L.Localizer -> RT.Context -> Diff -> Pair D.Doc
377diffToPair localizer ctx diff =
379 Similar tipe1 tipe2 ->
380 Pair (toDoc localizer ctx tipe1) (toDoc localizer ctx tipe2) Bag.empty
382 DiffLambda _ a b cs ->
384 <$> diffToPair localizer RT.Func a
385 <*> diffToPair localizer RT.Func b
386 <*> traverse (diffToPair localizer RT.Func) cs
388 DiffType _ home name args ->
389 RT.apply ctx (nameToDoc localizer home name)
390 <$> traverse (diffToPair localizer RT.App) args
392 DiffRecord _ left both right ext1 ext2 ->
393 diffRecord localizer left both right ext1 ext2
395 DiffTuple _ a b maybeC ->
397 <$> diffToPair localizer RT.None a
398 <*> diffToPair localizer RT.None b
399 <*> traverse (diffToPair localizer RT.None) (Maybe.maybeToList maybeC)
402 case (tipe1, tipe2) of
403 (Lambda a b cs, Lambda x y zs) ->
404 diffLambda localizer ctx (a:b:cs) (x:y:zs)
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)
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)
414 doc1 = D.dullyellow (toDoc localizer ctx tipe1)
415 doc2 = D.dullyellow (toDoc localizer ctx tipe2)
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
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
438isBool :: ModuleName.Canonical -> N.Name -> Bool
440 home == ModuleName.basics && name == N.bool
443isInt :: ModuleName.Canonical -> N.Name -> Bool
445 home == ModuleName.basics && name == N.int
448isFloat :: ModuleName.Canonical -> N.Name -> Bool
450 home == ModuleName.basics && name == N.float
453isString :: ModuleName.Canonical -> N.Name -> Bool
455 home == ModuleName.string && name == N.string
458isChar :: ModuleName.Canonical -> N.Name -> Bool
460 home == ModuleName.char && name == N.char
463isMaybe :: ModuleName.Canonical -> N.Name -> Bool
465 home == ModuleName.maybe && name == N.maybe
468isList :: ModuleName.Canonical -> N.Name -> Bool
470 home == ModuleName.list && name == N.list
473yellowApply :: L.Localizer -> RT.Context -> ModuleName.Canonical -> N.Name -> Type -> D.Doc
474yellowApply localizer ctx home name tipe =
476 (D.dullyellow (nameToDoc localizer home name))
477 [toDoc localizer RT.App tipe]
488-- length types1 /= length types2
490diffLambda :: L.Localizer -> RT.Context -> [Type] -> [Type] -> Pair D.Doc
491diffLambda localizer ctx types1 types2 =
493 (result1:revArgs1) = reverse types1
494 (result2:revArgs2) = reverse types2
496 numArgs1 = length revArgs1
497 numArgs2 = length revArgs2
499 diff = toDiff result1 result2
501 (Pair r1 r2 _) = diffToPair localizer RT.Func diff
503 if isSimilar diff then
505 if numArgs1 < numArgs2 then
506 diffArgMismatch localizer ctx revArgs1 r1 revArgs2 r2
508 diffArgMismatch localizer ctx revArgs2 r2 revArgs1 r1
512 (a1:b1:cs1) = reverse (r1 : map (toDoc localizer RT.Func) revArgs1)
513 (a2:b2:cs2) = reverse (r2 : map (toDoc localizer RT.Func) revArgs2)
516 (D.dullyellow (RT.lambda ctx a1 b1 cs1))
517 (D.dullyellow (RT.lambda ctx a2 b2 cs2))
518 (Bag.one ReturnMismatch)
523-- length shortRevArgs >= 2
524-- length longRevArgs >= 2
526diffArgMismatch :: L.Localizer -> RT.Context -> [Type] -> D.Doc -> [Type] -> D.Doc -> Pair D.Doc
527diffArgMismatch localizer ctx shortRevArgs shortResult longRevArgs longResult =
528 case toGreedyMatch localizer shortRevArgs longRevArgs of
529 Just (GreedyMatch shortRevArgDocs longRevArgDocs) ->
531 (a:b:cs) = reverse (shortResult:shortRevArgDocs)
532 (x:y:zs) = reverse (longResult:longRevArgDocs)
535 (RT.lambda ctx a b cs)
536 (RT.lambda ctx x y zs)
537 (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
540 case toGreedyMatch localizer (reverse shortRevArgs) (reverse longRevArgs) of
541 Just (GreedyMatch shortArgDocs longArgDocs) ->
543 (a:b:cs) = shortArgDocs ++ [shortResult]
544 (x:y:zs) = longArgDocs ++ [longResult]
547 (RT.lambda ctx a b cs)
548 (RT.lambda ctx x y zs)
549 (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
554 D.dullyellow (toDoc localizer RT.Func tipe)
556 (a:b:cs) = reverse (shortResult : map toYellowDoc shortRevArgs)
557 (x:y:zs) = reverse (longResult : map toYellowDoc longRevArgs )
560 (RT.lambda ctx a b cs)
561 (RT.lambda ctx x y zs)
562 (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
570 GreedyMatch [D.Doc] [D.Doc]
575-- length shorterArgs < length longerArgs
577toGreedyMatch :: L.Localizer -> [Type] -> [Type] -> Maybe GreedyMatch
578toGreedyMatch localizer shorterArgs longerArgs =
579 toGreedyMatchHelp localizer shorterArgs longerArgs (GreedyMatch [] [])
582toGreedyMatchHelp :: L.Localizer -> [Type] -> [Type] -> GreedyMatch -> Maybe GreedyMatch
583toGreedyMatchHelp localizer shorterArgs longerArgs match@(GreedyMatch shorterDocs longerDocs) =
586 D.dullyellow (toDoc localizer RT.Func tipe)
588 case (shorterArgs, longerArgs) of
592 toGreedyMatchHelp localizer xs ys $
594 (toDoc localizer RT.Func a : shorterDocs)
595 (toDoc localizer RT.Func b : longerDocs)
598 toGreedyMatchHelp localizer shorterArgs ys $
599 GreedyMatch shorterDocs (toYellowDoc y : longerDocs)
605 Just (GreedyMatch shorterDocs (map toYellowDoc longerArgs))
618 -> Map.Map N.Name Diff
623diffRecord localizer only1 both only2 ext1 ext2 =
624 if null only1 && null only2 then
625 case findBadOverlaps localizer both of
627 case diffExt ext1 ext2 of
630 (toBoringRecord (Map.size both) ext1)
631 (toBoringRecord (Map.size both) ext2)
634 ExtDifferent maybeExt1 maybeExt2 problems ->
636 (RT.record [] (fmap (D.dullyellow . D.fromName) maybeExt1))
637 (RT.record [] (fmap (D.dullyellow . D.fromName) maybeExt2))
640 overlaps@(bad:bads) ->
641 if length overlaps < Map.size both then
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))
648 (toOverlapRecord _doc1 bad bads ext1)
649 (toOverlapRecord _doc2 bad bads ext2)
650 (foldr Bag.append Bag.empty (map _problemBag overlaps))
654 (toMissingDoc (Map.size both) only1 ext1)
655 (toMissingDoc (Map.size both) only2 ext2)
656 (Bag.one (FieldMismatch only1 only2))
659toOverlapDoc :: (BadOverlap -> D.Doc) -> BadOverlap -> (D.Doc, D.Doc)
660toOverlapDoc getDoc overlap@(BadOverlap field _ _ _) =
661 (D.fromName field, getDoc overlap)
664toOverlapRecord :: (BadOverlap -> D.Doc) -> BadOverlap -> [BadOverlap] -> Extension -> D.Doc
665toOverlapRecord getDoc bad bads ext =
666 let go = toOverlapDoc getDoc in
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)
673toMissingDoc :: Int -> [N.Name] -> Extension -> D.Doc
674toMissingDoc numSharedFields uniqueFields ext =
675 case map emphasizeFieldName uniqueFields of
677 toBoringRecord numSharedFields ext
680 if length uniqueFields < numSharedFields then
681 RT.recordSnippet doc docs
684 Closed -> RT.record (doc:docs) Nothing
685 FlexOpen _ -> RT.recordSnippet doc docs
686 RigidOpen _ -> RT.recordSnippet doc docs
689emphasizeFieldName :: N.Name -> (D.Doc, D.Doc)
690emphasizeFieldName field =
691 ( D.dullyellow (D.fromName field), "..." )
694toBoringRecord :: Int -> Extension -> D.Doc
695toBoringRecord numFields ext =
697 Closed -> if numFields == 0 then "{}" else "{ ... }"
698 FlexOpen _ -> "{ ... }"
699 RigidOpen _ -> "{ ... }"
703-- DIFF RECORD EXTENSION
706isExtSimilar :: Extension -> Extension -> Bool
707isExtSimilar ext1 ext2 =
708 case diffExt ext1 ext2 of
712 ExtDifferent _ _ _ ->
718 | ExtDifferent (Maybe N.Name) (Maybe N.Name) (Bag.Bag Problem)
721diffExt :: Extension -> Extension -> ExtDiff
724 different x y = ExtDifferent x y Bag.empty
730 FlexOpen y -> different Nothing (Just y)
731 RigidOpen y -> different Nothing (Just y)
735 Closed -> different (Just x) Nothing
736 FlexOpen _ -> ExtSimilar
737 RigidOpen _ -> ExtSimilar
741 Closed -> different (Just x) Nothing
742 FlexOpen _ -> ExtSimilar
747 ExtDifferent (Just x) (Just y) (Bag.one (BadRigidVar x (RigidVar y)))
759 , _problemBag :: Bag.Bag Problem
763findBadOverlaps :: L.Localizer -> Map.Map N.Name Diff -> [BadOverlap]
764findBadOverlaps localizer overlaps =
765 Map.foldrWithKey (addBadOverlap localizer) [] overlaps
768addBadOverlap :: L.Localizer -> N.Name -> Diff -> [BadOverlap] -> [BadOverlap]
769addBadOverlap localizer field diff badOverlaps =
770 if isSimilar diff then
774 (Pair aDoc bDoc problems) = diffToPair localizer RT.None diff
776 BadOverlap field aDoc bDoc problems : badOverlaps
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