1{-# OPTIONS_GHC -Wall #-}
2module Transform.Check (mistakes) where
4import qualified Data.List as List
5import qualified Data.Maybe as Maybe
6import qualified Data.Set as Set
8import qualified AST.Expression.Valid as Valid
9import qualified AST.Declaration as D
10import qualified AST.Pattern as Pattern
11import qualified AST.Type as T
12import qualified Transform.Expression as Expr
15import Elm.Utils ((|>))
16import Text.PrettyPrint as P
19mistakes :: [D.ValidDecl] -> [Doc]
22 [ illFormedTypeDecls decls
23 , map P.text (duplicateTypeDeclarations decls)
24 , map P.text (duplicateValues decls)
30dups :: Ord a => [a] -> [a]
34 |> filter ((>1) . length)
38duplicateValues :: [D.ValidDecl] -> [String]
39duplicateValues decls =
40 map msg (dups (portNames ++ concatMap Pattern.boundVarList defPatterns)) ++
41 case mapM exprDups defExprs of
42 Left name -> [msg name]
47 "Name Collision: There can only be one definition of '" ++ x ++ "'."
49 (defPatterns, defExprs) =
50 unzip [ (pat,expr) | D.Definition (Valid.Definition pat expr _) <- decls ]
53 [ D.validPortName port | D.Port port <- decls ]
55 exprDups :: Valid.Expr -> Either String Valid.Expr
57 Expr.crawlLet defsDups expr
59 defsDups :: [Valid.Def] -> Either String [Valid.Def]
61 let varsIn (Valid.Definition pattern _ _) =
62 Pattern.boundVarList pattern
64 case dups (concatMap varsIn defs) of
69duplicateTypeDeclarations :: [D.ValidDecl] -> [String]
70duplicateTypeDeclarations decls =
71 map dupTypeError (dups (typeNames ++ aliasNames))
72 ++ map dupCtorError (dups (ctorNames ++ aliasNames))
75 [ name | D.Datatype name _ _ <- decls ]
78 [ name | D.TypeAlias name _ _ <- decls ]
81 concat [ map fst patterns | D.Datatype _ _ patterns <- decls ]
84dupTypeError :: String -> String
86 "Name Collision: There can only be one type named '" ++ name ++ "'"
89dupCtorError :: String -> String
91 "Name Collision: There can only be one constructor named '" ++ name ++ "'.\n"
92 ++ " Constructors are created for record type aliases and for union types, so\n"
93 ++ " something should be renamed or moved to a different module."
96-- FREE TYPE VARIABLES IN TYPE DECLARATIONS
98illFormedTypeDecls :: [D.ValidDecl] -> [Doc]
99illFormedTypeDecls decls =
100 map report (Maybe.mapMaybe isIllFormed (aliases ++ adts))
103 [ (decl, tvars, [tipe]) | decl@(D.TypeAlias _ tvars tipe) <- decls ]
106 [ (decl, tvars, concatMap snd ctors) | decl@(D.Datatype _ tvars ctors) <- decls ]
111 Set.union (freeVars t1) (freeVars t2)
120 Set.unions (map freeVars (t:ts))
122 T.Record fields ext ->
123 let ext' = maybe Set.empty freeVars ext
125 Set.unions (ext' : map (freeVars . snd) fields)
127 T.Aliased _ args t ->
128 freeVars (T.dealias args t)
130 undeclared tvars tipes =
131 Set.difference used declared
133 used = Set.unions (map freeVars tipes)
134 declared = Set.fromList tvars
136 isIllFormed (decl, tvars, tipes) =
137 let unbound = undeclared tvars tipes in
140 else Just (decl, Set.toList unbound)
142 report (decl, tvars) =
143 P.vcat [ P.text $ "Error: type variable" ++ listing ++ " unbound in:"
145 , nest 4 (pretty decl) ]
149 [tvar] -> " " ++ quote tvar ++ " is"
150 _ -> "s" ++ addCommas (map ((++) " ") (addAnd (map quote tvars))) ++ " are"
153 | length xs < 3 = concat xs
154 | otherwise = List.intercalate "," xs
158 | otherwise = zipWith (++) (replicate (length xs - 1) "" ++ ["and "]) xs
160 quote tvar = "'" ++ tvar ++ "'"
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