1module Transform.Check (mistakes) where
3import Transform.SortDefinitions (boundVars)
4import SourceSyntax.Declaration (Declaration(..))
5import SourceSyntax.Expression
6import SourceSyntax.Pattern
7import SourceSyntax.Location
8import SourceSyntax.PrettyPrint
9import qualified SourceSyntax.Type as T
10import Data.List as List
11import qualified Data.Map as Map
12import qualified Data.Maybe as Maybe
13import qualified Data.Set as Set
14import Text.PrettyPrint as P
17mistakes :: [Declaration t v] -> [Doc]
19 concat [ infiniteTypeAliases decls
20 , illFormedTypes decls
21 , map P.text (duplicateConstructors decls)
22 , map P.text (concatMap findErrors (getLets decls)) ]
24 findErrors defs = duplicates defs ++ badOrder defs
26getLets :: [Declaration t v] -> [[Def t v]]
27getLets decls = defs : concatMap defLets defs
29 defs = [ d | Definition d <- decls ]
33 TypeAnnotation _ _ -> []
34 Def _ expr -> exprLets expr
39 Lambda p e -> exprLets e
40 Binop op e1 e2 -> exprLets e1 ++ exprLets e2
41 Case e cases -> exprLets e ++ concatMap (exprLets . snd) cases
42 Data name es -> concatMap exprLets es
44 Range e1 e2 -> exprLets e1 ++ exprLets e2
45 ExplicitList es -> concatMap exprLets es
46 App e1 e2 -> exprLets e1 ++ exprLets e2
47 MultiIf branches -> concatMap (\(b,e) -> exprLets b ++ exprLets e) branches
48 Access e lbl -> exprLets e
49 Remove e lbl -> exprLets e
50 Insert e lbl v -> exprLets e ++ exprLets v
51 Modify e fields -> exprLets e ++ concatMap (exprLets . snd) fields
52 Record fields -> concatMap (exprLets . snd) fields
53 Markdown uid md es -> []
54 Let defs body -> [defs] ++ exprLets body
56dups :: Eq a => [a] -> [a]
57dups = map head . filter ((>1) . length) . List.group
59dupErr :: String -> String -> String
61 "Syntax Error: There can only be one " ++ err ++ " '" ++ x ++ "'."
63duplicates :: [Def t v] -> [String]
65 map defMsg (dups definitions) ++ map annMsg (dups annotations)
67 annotations = List.sort [ name | TypeAnnotation name _ <- defs ]
68 definitions = List.sort $ concatMap Set.toList [ boundVars pattern | Def pattern _ <- defs ]
69 defMsg = dupErr "definition of"
70 annMsg = dupErr "type annotation for"
72duplicateConstructors :: [Declaration t v] -> [String]
73duplicateConstructors decls =
74 map typeMsg (dups typeCtors) ++ map dataMsg (dups dataCtors)
76 typeCtors = List.sort [ name | Datatype name _ _ <- decls ]
77 dataCtors = List.sort . concat $
78 [ map fst patterns | Datatype _ _ patterns <- decls ]
79 dataMsg = dupErr "definition of data constructor"
80 typeMsg = dupErr "definition of type constructor"
82badOrder :: [Def t v] -> [String]
83badOrder defs = go defs
85 msg x = "Syntax Error: The type annotation for '" ++ x ++
86 "' must be directly above its definition."
90 TypeAnnotation name _ : Def (PVar name') _ : rest
91 | name == name' -> go rest
93 TypeAnnotation name _ : rest -> [msg name] ++ go rest
99illFormedTypes :: [Declaration t v] -> [Doc]
100illFormedTypes decls = map report (Maybe.mapMaybe isIllFormed (aliases ++ adts))
102 aliases = [ (decl, tvars, [tipe]) | decl@(TypeAlias _ tvars tipe) <- decls ]
103 adts = [ (decl, tvars, concatMap snd ctors) | decl@(Datatype _ tvars ctors) <- decls ]
107 T.Lambda t1 t2 -> Set.union (freeVars t1) (freeVars t2)
108 T.Var x -> Set.singleton x
109 T.Data _ ts -> Set.unions (map freeVars ts)
110 T.EmptyRecord -> Set.empty
111 T.Record fields ext -> Set.unions (freeVars ext : map (freeVars . snd) fields)
113 undeclared tvars tipes = Set.difference used declared
115 used = Set.unions (map freeVars tipes)
116 declared = Set.fromList tvars
118 isIllFormed (decl, tvars, tipes) =
119 let unbound = undeclared tvars tipes in
120 if Set.null unbound then Nothing
121 else Just (decl, Set.toList unbound)
123 report (decl, tvars) =
124 P.vcat [ P.text $ "Error: type variable" ++ listing ++ " unbound in:"
126 , nest 4 (pretty decl) ]
130 [tvar] -> " " ++ quote tvar ++ " is"
131 _ -> "s" ++ addCommas (map ((++) " ") (addAnd (map quote tvars))) ++ " are"
134 | length xs < 3 = concat xs
135 | otherwise = intercalate "," xs
139 | otherwise = zipWith (++) (replicate (length xs - 1) "" ++ ["and "]) xs
141 quote tvar = "'" ++ tvar ++ "'"
144infiniteTypeAliases :: [Declaration t v] -> [Doc]
145infiniteTypeAliases decls =
146 [ report decl | decl@(TypeAlias name _ tipe) <- decls, isInfinite name tipe ]
148 isInfinite name tipe =
149 let infinite = isInfinite name in
151 T.Lambda a b -> infinite a || infinite b
153 T.Data name' ts -> name == name' || any infinite ts
154 T.EmptyRecord -> False
155 T.Record fields ext -> infinite ext || any (infinite . snd) fields
157 report decl@(TypeAlias name args tipe) =
158 P.vcat [ P.text $ eightyCharLines 0 msg1
160 , P.text $ eightyCharLines 0 msg2
161 , indented (Datatype name args [(name,[tipe])])
162 , P.text $ eightyCharLines 0 msg3 ++ "\n"
165 indented decl = P.text "\n " <> pretty decl <> P.text "\n"
167 msg1 = "Type alias '" ++ name ++ "' is an infinite type. " ++
168 "Notice that it appears in its own definition, so when \
169 \you expand it, it just keeps getting bigger:"
170 msg2 = "Try this instead:"
171 msg3 = "It looks very similar, but an algebraic data type (ADT) \
172 \actually creates a new type. Unlike with a type alias, this \
173 \freshly created type is meaningful on its own, so an ADT \
174 \does not need to be expanded."
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