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]
188 | FieldsMissing [N.Name]
191instance Functor Diff where
192 fmap func (Diff a b status) =
193 Diff (func a) (func b) status
196instance Applicative Diff where
200 (<*>) (Diff aFunc bFunc status1) (Diff aArg bArg status2) =
201 Diff (aFunc aArg) (bFunc bArg) (merge status1 status2)
204merge :: Status -> Status -> Status
205merge status1 status2 =
210 Different problems1 ->
215 Different problems2 ->
216 Different (Bag.append problems1 problems2)
223toComparison :: L.Localizer -> Type -> Type -> (D.Doc, D.Doc, [Problem])
224toComparison localizer tipe1 tipe2 =
225 case toDiff localizer RT.None tipe1 tipe2 of
226 Diff doc1 doc2 Similar ->
229 Diff doc1 doc2 (Different problems) ->
230 (doc1, doc2, Bag.toList problems)
233toDiff :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
234toDiff localizer ctx tipe1 tipe2 =
235 case (tipe1, tipe2) of
236 (Unit , Unit ) -> same localizer ctx tipe1
237 (Error , Error ) -> same localizer ctx tipe1
238 (Infinite, Infinite) -> same localizer ctx tipe1
240 (FlexVar x, FlexVar y) | x == y -> same localizer ctx tipe1
241 (FlexSuper _ x, FlexSuper _ y) | x == y -> same localizer ctx tipe1
242 (RigidVar x, RigidVar y) | x == y -> same localizer ctx tipe1
243 (RigidSuper _ x, RigidSuper _ y) | x == y -> same localizer ctx tipe1
245 (FlexVar _, _ ) -> similar localizer ctx tipe1 tipe2
246 (_ , FlexVar _) -> similar localizer ctx tipe1 tipe2
248 (FlexSuper s _, t ) | isSuper s t -> similar localizer ctx tipe1 tipe2
249 (t , FlexSuper s _) | isSuper s t -> similar localizer ctx tipe1 tipe2
251 (Lambda a b cs, Lambda x y zs) ->
252 if length cs == length zs then
254 <$> toDiff localizer RT.Func a x
255 <*> toDiff localizer RT.Func b y
256 <*> sequenceA (zipWith (toDiff localizer RT.Func) cs zs)
258 diffLambda localizer ctx a b cs x y zs
260 (Tuple a b Nothing, Tuple x y Nothing) ->
262 <$> toDiff localizer RT.None a x
263 <*> toDiff localizer RT.None b y
266 (Tuple a b (Just c), Tuple x y (Just z)) ->
268 <$> toDiff localizer RT.None a x
269 <*> toDiff localizer RT.None b y
270 <*> ((:[]) <$> toDiff localizer RT.None c z)
272 (Record fields1 ext1, Record fields2 ext2) ->
273 diffRecord localizer fields1 ext1 fields2 ext2
275 (Type home1 name1 args1, Type home2 name2 args2) | home1 == home2 && name1 == name2 ->
276 RT.apply ctx (nameToDoc localizer home1 name1)
277 <$> sequenceA (zipWith (toDiff localizer RT.App) args1 args2)
279 (Alias home1 name1 args1 _, Alias home2 name2 args2 _) | home1 == home2 && name1 == name2 ->
280 RT.apply ctx (nameToDoc localizer home1 name1)
281 <$> sequenceA (zipWith (toDiff localizer RT.App) (map snd args1) (map snd args2))
283 -- start trying to find specific problems
285 (Type home name [t1], t2) | isMaybe home name && isSimilar (toDiff localizer ctx t1 t2) ->
287 (RT.apply ctx (D.dullyellow (nameToDoc localizer home name)) [toDoc localizer RT.App t1])
288 (toDoc localizer ctx t2)
289 (Bag.one AnythingFromMaybe)
291 (t1, Type home name [t2]) | isList home name && isSimilar (toDiff localizer ctx t1 t2) ->
293 (toDoc localizer ctx t1)
294 (RT.apply ctx (D.dullyellow (nameToDoc localizer home name)) [toDoc localizer RT.App t2])
295 (Bag.one AnythingToList)
297 (Alias home name args t1, t2) ->
298 case diffAliasedRecord localizer t1 t2 of
299 Just (Diff _ doc2 status) ->
300 Diff (D.dullyellow (aliasToDoc localizer ctx home name args)) doc2 status
304 (D.dullyellow (toDoc localizer ctx tipe1))
305 (D.dullyellow (toDoc localizer ctx tipe2))
308 (t1, Alias home name args t2) ->
309 case diffAliasedRecord localizer t1 t2 of
310 Just (Diff doc1 _ status) ->
311 Diff doc1 (D.dullyellow (aliasToDoc localizer ctx home name args)) status
315 (D.dullyellow (toDoc localizer ctx tipe1))
316 (D.dullyellow (toDoc localizer ctx tipe2))
321 doc1 = D.dullyellow (toDoc localizer ctx tipe1)
322 doc2 = D.dullyellow (toDoc localizer ctx tipe2)
324 different doc1 doc2 $
326 (RigidVar x, other) -> Bag.one $ BadRigidVar x other
327 (FlexSuper s x, other) -> Bag.one $ BadFlexSuper s x other
328 (RigidSuper s x, other) -> Bag.one $ BadRigidSuper s x other
329 (other, RigidVar x) -> Bag.one $ BadRigidVar x other
330 (other, FlexSuper s x) -> Bag.one $ BadFlexSuper s x other
331 (other, RigidSuper s x) -> Bag.one $ BadRigidSuper s x other
333 (Type home1 name1 [], Type home2 name2 [])
334 | isInt home1 name1 && isFloat home2 name2 -> Bag.one IntFloat
335 | isFloat home1 name1 && isInt home2 name2 -> Bag.one IntFloat
336 | isInt home1 name1 && isString home2 name2 -> Bag.one StringFromInt
337 | isFloat home1 name1 && isString home2 name2 -> Bag.one StringFromFloat
338 | isString home1 name1 && isInt home2 name2 -> Bag.one StringToInt
339 | isString home1 name1 && isFloat home2 name2 -> Bag.one StringToFloat
340 | isBool home2 name2 -> Bag.one AnythingToBool
350same :: L.Localizer -> RT.Context -> Type -> Diff D.Doc
351same localizer ctx tipe =
353 doc = toDoc localizer ctx tipe
358similar :: L.Localizer -> RT.Context -> Type -> Type -> Diff D.Doc
359similar localizer ctx t1 t2 =
360 Diff (toDoc localizer ctx t1) (toDoc localizer ctx t2) Similar
363different :: a -> a -> Bag.Bag Problem -> Diff a
364different a b problems =
365 Diff a b (Different problems)
368isSimilar :: Diff a -> Bool
369isSimilar (Diff _ _ status) =
379isBool :: ModuleName.Canonical -> N.Name -> Bool
381 home == ModuleName.basics && name == N.bool
384isInt :: ModuleName.Canonical -> N.Name -> Bool
386 home == ModuleName.basics && name == N.int
389isFloat :: ModuleName.Canonical -> N.Name -> Bool
391 home == ModuleName.basics && name == N.float
394isString :: ModuleName.Canonical -> N.Name -> Bool
396 home == ModuleName.string && name == N.string
399isChar :: ModuleName.Canonical -> N.Name -> Bool
401 home == ModuleName.char && name == N.char
404isMaybe :: ModuleName.Canonical -> N.Name -> Bool
406 home == ModuleName.maybe && name == N.maybe
409isList :: ModuleName.Canonical -> N.Name -> Bool
411 home == ModuleName.list && name == N.list
418isSuper :: Super -> Type -> Bool
420 case iteratedDealias tipe of
423 Number -> isInt h n || isFloat h n
424 Comparable -> isInt h n || isFloat h n || isString h n || isChar h n || isList h n && isSuper super (head args)
425 Appendable -> isString h n || isList h n
426 CompAppend -> isString h n || isList h n && isSuper Comparable (head args)
433-- DIFF ALIASED RECORD
436diffAliasedRecord :: L.Localizer -> Type -> Type -> Maybe (Diff D.Doc)
437diffAliasedRecord localizer t1 t2 =
438 case (iteratedDealias t1, iteratedDealias t2) of
439 (Record fields1 ext1, Record fields2 ext2) ->
440 Just (diffRecord localizer fields1 ext1 fields2 ext2)
452-- length cs1 /= length cs2
454diffLambda :: L.Localizer -> RT.Context -> Type -> Type -> [Type] -> Type -> Type -> [Type] -> Diff D.Doc
455diffLambda localizer ctx a1 b1 cs1 a2 b2 cs2 =
457 (result1:revArgs1) = reverse (a1:b1:cs1)
458 (result2:revArgs2) = reverse (a2:b2:cs2)
460 numArgs1 = length revArgs1
461 numArgs2 = length revArgs2
463 case toDiff localizer RT.Func result1 result2 of
464 Diff resultDoc1 resultDoc2 Similar ->
465 if numArgs1 < numArgs2 then
466 diffArgMismatch localizer ctx revArgs1 resultDoc1 revArgs2 resultDoc2
469 diffArgMismatch localizer ctx revArgs2 resultDoc2 revArgs1 resultDoc1
471 Diff resultDoc1 resultDoc2 (Different problems) ->
473 (a:b:cs) = reverse (resultDoc1 : map (toDoc localizer RT.Func) revArgs1)
474 (x:y:zs) = reverse (resultDoc2 : map (toDoc localizer RT.Func) revArgs2)
477 (D.dullyellow (RT.lambda ctx a b cs))
478 (D.dullyellow (RT.lambda ctx x y zs))
479 (Bag.append problems (Bag.one ReturnMismatch))
484-- length shortRevArgs >= 2
485-- length longRevArgs >= 2
486-- length shortRevArgs < length longRevArgs
488diffArgMismatch :: L.Localizer -> RT.Context -> [Type] -> D.Doc -> [Type] -> D.Doc -> Diff D.Doc
489diffArgMismatch localizer ctx shortRevArgs shortResult longRevArgs longResult =
492 case toGreedyMatch localizer shortRevArgs longRevArgs of
493 Just (GreedyMatch shortRevArgDocs longRevArgDocs) ->
494 ( reverse (shortResult:shortRevArgDocs)
495 , reverse (longResult:longRevArgDocs)
499 case toGreedyMatch localizer (reverse shortRevArgs) (reverse longRevArgs) of
500 Just (GreedyMatch shortArgDocs longArgDocs) ->
501 ( shortArgDocs ++ [shortResult]
502 , longArgDocs ++ [longResult]
508 D.dullyellow (toDoc localizer RT.Func tipe)
510 ( reverse (shortResult : map toYellowDoc shortRevArgs)
511 , reverse (longResult : map toYellowDoc longRevArgs )
515 (RT.lambda ctx a b cs)
516 (RT.lambda ctx x y zs)
517 (Bag.one (MissingArgs (length longRevArgs - length shortRevArgs)))
525 GreedyMatch [D.Doc] [D.Doc]
530-- length shorterArgs < length longerArgs
532toGreedyMatch :: L.Localizer -> [Type] -> [Type] -> Maybe GreedyMatch
533toGreedyMatch localizer shorterArgs longerArgs =
534 toGreedyMatchHelp localizer shorterArgs longerArgs (GreedyMatch [] [])
537toGreedyMatchHelp :: L.Localizer -> [Type] -> [Type] -> GreedyMatch -> Maybe GreedyMatch
538toGreedyMatchHelp localizer shorterArgs longerArgs match@(GreedyMatch shorterDocs longerDocs) =
541 D.dullyellow (toDoc localizer RT.Func tipe)
543 case (shorterArgs, longerArgs) of
545 case toDiff localizer RT.Func x y of
547 toGreedyMatchHelp localizer xs ys $
548 GreedyMatch (a:shorterDocs) (b:longerDocs)
550 Diff _ _ (Different _) ->
551 toGreedyMatchHelp localizer shorterArgs ys $
552 GreedyMatch shorterDocs (toYellowDoc y : longerDocs)
558 Just (GreedyMatch shorterDocs (map toYellowDoc longerArgs))
568diffRecord :: L.Localizer -> Map.Map N.Name Type -> Extension -> Map.Map N.Name Type -> Extension -> Diff D.Doc
569diffRecord localizer fields1 ext1 fields2 ext2 =
571 toUnknownDocs field tipe =
572 ( D.dullyellow (D.fromName field), toDoc localizer RT.None tipe )
574 toOverlapDocs field t1 t2 =
575 (,) (D.fromName field) <$> toDiff localizer RT.None t1 t2
577 left = Map.mapWithKey toUnknownDocs (Map.difference fields1 fields2)
578 both = Map.intersectionWithKey toOverlapDocs fields1 fields2
579 right = Map.mapWithKey toUnknownDocs (Map.difference fields2 fields1)
583 if Map.null left && Map.null right then
588 <*> Diff left right (Different Bag.empty)
590 (Diff doc1 doc2 status) =
593 <*> extToDiff ext1 ext2
595 Diff doc1 doc2 $ merge status $
596 case (hasFixedFields ext1, hasFixedFields ext2) of
598 case Map.lookupMin left of
599 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
603 else Different $ Bag.one $ FieldsMissing (Map.keys right)
606 case Map.lookupMin left of
607 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields2)
611 case Map.lookupMin right of
612 Just (f,_) -> Different $ Bag.one $ FieldTypo f (Map.keys fields1)
619hasFixedFields :: Extension -> Bool
628-- DIFF RECORD EXTENSION
631extToDiff :: Extension -> Extension -> Diff (Maybe D.Doc)
634 status = extToStatus ext1 ext2
635 extDoc1 = extToDoc ext1
636 extDoc2 = extToDoc ext2
640 Diff extDoc1 extDoc2 status
643 Diff (D.dullyellow <$> extDoc1) (D.dullyellow <$> extDoc2) status
646extToStatus :: Extension -> Extension -> Status
647extToStatus ext1 ext2 =
652 FlexOpen _ -> Similar
653 RigidOpen _ -> Different Bag.empty
660 Closed -> Different Bag.empty
661 FlexOpen _ -> Similar
665 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