1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
20import qualified Data.Map as Map
21import qualified Data.Maybe as Maybe
23import qualified AST.Module.Name as ModuleName
24import qualified Data.Bag as Bag
25import qualified Elm.Name as N
26import qualified Reporting.Doc as D
27import qualified Reporting.Render.Type as RT
28import qualified Reporting.Render.Type.Localizer as L
36 = Lambda Type Type [Type]
40 | FlexSuper Super N.Name
42 | RigidSuper Super N.Name
43 | Type ModuleName.Canonical N.Name [Type]
44 | Record (Map.Map N.Name Type) Extension
46 | Tuple Type Type (Maybe Type)
47 | Alias ModuleName.Canonical N.Name [(N.Name, Type)] Type
64iteratedDealias :: Type -> Type
78nameToDoc :: L.Localizer -> ModuleName.Canonical -> N.Name -> D.Doc
79nameToDoc localizer (ModuleName.Canonical _ home) name =
80 L.toDoc localizer home name
83toDoc :: L.Localizer -> RT.Context -> Type -> D.Doc
84toDoc localizer ctx tipe =
88 (toDoc localizer RT.Func a)
89 (toDoc localizer RT.Func b)
90 (map (toDoc localizer RT.Func) cs)
110 Type home name args ->
112 (nameToDoc localizer home name)
113 (map (toDoc localizer RT.App) args)
116 RT.record (fieldsToDocs localizer fields) (extToDoc ext)
123 (toDoc localizer RT.None a)
124 (toDoc localizer RT.None b)
125 (map (toDoc localizer RT.None) (Maybe.maybeToList maybeC))
127 Alias home name args _ ->
128 aliasToDoc localizer ctx home name args
131aliasToDoc :: L.Localizer -> RT.Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Type)] -> D.Doc
132aliasToDoc localizer ctx home name args =
134 (nameToDoc localizer home name)
135 (map (toDoc localizer RT.App . snd) args)
138fieldsToDocs :: L.Localizer -> Map.Map N.Name Type -> [(D.Doc, D.Doc)]
139fieldsToDocs localizer fields =
140 Map.foldrWithKey (addField localizer) [] fields
143addField :: L.Localizer -> N.Name -> Type -> [(D.Doc, D.Doc)] -> [(D.Doc, D.Doc)]
144addField localizer fieldName fieldType docs =
146 f = D.fromName fieldName
147 t = toDoc localizer RT.None fieldType
152extToDoc :: Extension -> Maybe D.Doc
156 FlexOpen x -> Just (D.fromName x)
157 RigidOpen x -> Just (D.fromName x)
170 | Different (Bag.Bag Problem)
184 | BadFlexSuper Super N.Name Type
185 | BadRigidVar N.Name Type
186 | BadRigidSuper Super N.Name Type
187 | FieldTypo N.Name [N.Name]
190instance Functor Diff where
191 fmap func (Diff a b status) =
192 Diff (func a) (func b) status
195instance Applicative Diff where
199 (<*>) (Diff aFunc bFunc status1) (Diff aArg bArg status2) =
200 Diff (aFunc aArg) (bFunc bArg) (merge status1 status2)
203merge :: Status -> Status -> Status
204merge status1 status2 =
209 Different problems1 ->
214 Different problems2 ->
215 Different (Bag.append problems1 problems2)
222toComparison :: L.Localizer -> Type -> Type -> (D.Doc, D.Doc, [Problem])
223toComparison localizer tipe1 tipe2 =
224 case toDiff localizer RT.None tipe1 tipe2 of
225 Diff doc1 doc2 Similar ->
228 Diff doc1 doc2 (Different problems) ->
229 (doc1, doc2, Bag.toList problems)
232toDiff :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
233toDiff 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
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
244 (FlexVar _, _ ) -> similar localizer ctx tipe1 tipe2
245 (_ , FlexVar _) -> 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 (nameToDoc 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 (nameToDoc 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 home name [t1], t2) | isMaybe home name && isSimilar (toDiff localizer ctx t1 t2) ->
283 (RT.apply ctx (D.dullyellow (nameToDoc localizer home name)) [toDoc localizer RT.App t1])
284 (toDoc localizer ctx t2)
285 (Bag.one AnythingFromMaybe)
287 (t1, Type home name [t2]) | isList home name && isSimilar (toDiff localizer ctx t1 t2) ->
289 (toDoc localizer ctx t1)
290 (RT.apply ctx (D.dullyellow (nameToDoc localizer home name)) [toDoc localizer RT.App t2])
291 (Bag.one AnythingToList)
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
300 (D.dullyellow (toDoc localizer ctx tipe1))
301 (D.dullyellow (toDoc localizer ctx tipe2))
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
311 (D.dullyellow (toDoc localizer ctx tipe1))
312 (D.dullyellow (toDoc localizer ctx tipe2))
317 doc1 = D.dullyellow (toDoc localizer ctx tipe1)
318 doc2 = D.dullyellow (toDoc localizer ctx tipe2)
320 different doc1 doc2 $
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
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
346same :: L.Localizer -> RT.Context -> Type -> Diff D.Doc
347same localizer ctx tipe =
349 doc = toDoc localizer ctx tipe
354similar :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
355similar localizer ctx t1 t2 =
356 Diff (toDoc localizer ctx t1) (toDoc localizer ctx t2) Similar
359different :: a -> a -> Bag.Bag Problem -> Diff a
360different a b problems =
361 Diff a b (Different problems)
364isSimilar :: Diff a -> Bool
365isSimilar (Diff _ _ status) =
375isBool :: ModuleName.Canonical -> N.Name -> Bool
377 home == ModuleName.basics && name == N.bool
380isInt :: ModuleName.Canonical -> N.Name -> Bool
382 home == ModuleName.basics && name == N.int
385isFloat :: ModuleName.Canonical -> N.Name -> Bool
387 home == ModuleName.basics && name == N.float
390isString :: ModuleName.Canonical -> N.Name -> Bool
392 home == ModuleName.string && name == N.string
395isChar :: ModuleName.Canonical -> N.Name -> Bool
397 home == ModuleName.char && name == N.char
400isMaybe :: ModuleName.Canonical -> N.Name -> Bool
402 home == ModuleName.maybe && name == N.maybe
405isList :: ModuleName.Canonical -> N.Name -> Bool
407 home == ModuleName.list && name == N.list
411-- DIFF ALIASED RECORD
414diffAliasedRecord :: L.Localizer -> Type -> Type -> Maybe (Diff D.Doc)
415diffAliasedRecord 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)
430-- length cs1 /= length cs2
432diffLambda :: L.Localizer -> RT.Context -> Type -> Type -> [Type] -> Type -> Type -> [Type] -> Diff D.Doc
433diffLambda localizer ctx a1 b1 cs1 a2 b2 cs2 =
435 (result1:revArgs1) = reverse (a1:b1:cs1)
436 (result2:revArgs2) = reverse (a2:b2:cs2)
438 numArgs1 = length revArgs1
439 numArgs2 = length revArgs2
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
447 diffArgMismatch localizer ctx revArgs2 resultDoc2 revArgs1 resultDoc1
449 Diff resultDoc1 resultDoc2 (Different problems) ->
451 (a:b:cs) = reverse (resultDoc1 : map (toDoc localizer RT.Func) revArgs1)
452 (x:y:zs) = reverse (resultDoc2 : map (toDoc localizer RT.Func) revArgs2)
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))
462-- length shortRevArgs >= 2
463-- length longRevArgs >= 2
464-- length shortRevArgs < length longRevArgs
466diffArgMismatch :: L.Localizer -> RT.Context -> [Type] -> D.Doc -> [Type] -> D.Doc -> Diff D.Doc
467diffArgMismatch localizer ctx shortRevArgs shortResult longRevArgs longResult =
470 case toGreedyMatch localizer shortRevArgs longRevArgs of
471 Just (GreedyMatch shortRevArgDocs longRevArgDocs) ->
472 ( reverse (shortResult:shortRevArgDocs)
473 , reverse (longResult:longRevArgDocs)
477 case toGreedyMatch localizer (reverse shortRevArgs) (reverse longRevArgs) of
478 Just (GreedyMatch shortArgDocs longArgDocs) ->
479 ( shortArgDocs ++ [shortResult]
480 , longArgDocs ++ [longResult]
486 D.dullyellow (toDoc localizer RT.Func tipe)
488 ( reverse (shortResult : map toYellowDoc shortRevArgs)
489 , reverse (longResult : map toYellowDoc longRevArgs )
493 (RT.lambda ctx a b cs)
494 (RT.lambda ctx x y zs)
495 (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
503 GreedyMatch [D.Doc] [D.Doc]
508-- length shorterArgs < length longerArgs
510toGreedyMatch :: L.Localizer -> [Type] -> [Type] -> Maybe GreedyMatch
511toGreedyMatch localizer shorterArgs longerArgs =
512 toGreedyMatchHelp localizer shorterArgs longerArgs (GreedyMatch [] [])
515toGreedyMatchHelp :: L.Localizer -> [Type] -> [Type] -> GreedyMatch -> Maybe GreedyMatch
516toGreedyMatchHelp localizer shorterArgs longerArgs match@(GreedyMatch shorterDocs longerDocs) =
519 D.dullyellow (toDoc localizer RT.Func tipe)
521 case (shorterArgs, longerArgs) of
523 case toDiff localizer RT.Func x y of
525 toGreedyMatchHelp localizer xs ys $
526 GreedyMatch (a:shorterDocs) (b:longerDocs)
528 Diff _ _ (Different _) ->
529 toGreedyMatchHelp localizer shorterArgs ys $
530 GreedyMatch shorterDocs (toYellowDoc y : longerDocs)
536 Just (GreedyMatch shorterDocs (map toYellowDoc longerArgs))
546diffRecord :: L.Localizer -> Map.Map N.Name Type -> Extension -> Map.Map N.Name Type -> Extension -> Diff D.Doc
547diffRecord localizer fields1 ext1 fields2 ext2 =
549 toUnknownDocs field tipe =
550 ( D.dullyellow (D.fromName field), toDoc localizer RT.None tipe )
552 toOverlapDocs field t1 t2 =
553 (,) (D.fromName field) <$> toDiff localizer RT.None t1 t2
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)
561 if Map.null left && Map.null right then
566 <*> Diff left right (Different Bag.empty)
568 (Diff doc1 doc2 status) =
571 <*> extToDiff ext1 ext2
573 Diff doc1 doc2 $ merge status $
574 case (hasFixedFields ext1, hasFixedFields ext2) of
576 case Map.lookupMin left of
577 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
579 case Map.lookupMin right of
580 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields1)
584 case Map.lookupMin left of
585 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
589 case Map.lookupMin right of
590 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields1)
597hasFixedFields :: Extension -> Bool
606-- DIFF RECORD EXTENSION
609extToDiff :: Extension -> Extension -> Diff (Maybe D.Doc)
612 status = extToStatus ext1 ext2
613 extDoc1 = extToDoc ext1
614 extDoc2 = extToDoc ext2
618 Diff extDoc1 extDoc2 status
621 Diff (D.dullyellow <$> extDoc1) (D.dullyellow <$> extDoc2) status
624extToStatus :: Extension -> Extension -> Status
625extToStatus ext1 ext2 =
630 FlexOpen _ -> Similar
631 RigidOpen _ -> Different Bag.empty
638 Closed -> Different Bag.empty
639 FlexOpen _ -> Similar
643 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