@@ -8,11 +8,13 @@ import qualified Data.Aeson as Json
8import Data.Function (on)
8import Data.Function (on)
9import qualified Data.List as List
9import qualified Data.List as List
10import qualified Text.EditDistance as Dist
10import qualified Text.EditDistance as Dist
11+import qualified Text.PrettyPrint as P
12import qualified AST.Module as Module
13import qualified AST.Module as Module
13import qualified AST.Type as Type
14import qualified AST.Type as Type
14import qualified AST.Variable as Var
15import qualified AST.Variable as Var
15import Elm.Utils ((|>))
16import Elm.Utils ((|>))
17+import qualified Reporting.PrettyPrint as P
16import qualified Reporting.Region as R
18import qualified Reporting.Region as R
@@ -31,19 +33,20 @@ data VarError = VarError
31 { varKind :: String
33 { varKind :: String
32 , varName :: String
34 , varName :: String
33 , varProblem :: VarProblem
35 , varProblem :: VarProblem
36+ , varSuggestions :: [String]
37data VarProblem
40data VarProblem
38− = Ambiguous [String]
41+ = Ambiguous
39− | UnknownQualifier [Module.Name]
42+ | UnknownQualifier String
40− | QualifiedUnknown [String]
43+ | QualifiedUnknown String
41− | ExposedUnknown { closeExposed :: [String], closeQualified :: [String] }
44+ | ExposedUnknown
44−var :: String -> String -> VarProblem -> Error
47+variable :: String -> String -> VarProblem -> [String] -> Error
45−var kind name problem =
48+variable kind name problem suggestions =
46− Var (VarError kind name problem)
49+ Var (VarError kind name problem suggestions)
@@ -94,7 +97,7 @@ data PortError = PortError
94 , portIsInbound :: Bool
97 , portIsInbound :: Bool
95 , portRootType :: Type.Canonical
98 , portRootType :: Type.Canonical
96 , portLocalType :: Type.Canonical
99 , portLocalType :: Type.Canonical
97− , portMessage :: String
100+ , portMessage :: Maybe String
@@ -103,10 +106,10 @@ port
104 -> Type.Canonical
107 -> Type.Canonical
105 -> Type.Canonical
108 -> Type.Canonical
106− -> String
109+ -> Maybe String
108−port name isInbound rootType localType message =
111+port name isInbound rootType localType maybeMessage =
109− Port (PortError name isInbound rootType localType message)
112+ Port (PortError name isInbound rootType localType maybeMessage)
112-- NEARBY NAMES
115-- NEARBY NAMES
@@ -143,6 +146,107 @@ toJson err =
143 case err of
146 case err of
144 _ -> error "Canonicalize.toJson"
147 _ -> error "Canonicalize.toJson"
152+toHint :: Error -> String
155+ Var (VarError kind name problem suggestions) ->
156+ let var = kind ++ "'" ++ name ++ "'"
160+ "This usage of " ++ var ++ " is ambiguous"
161+ ++ maybeYouWant "\n\n" suggestions
163+ UnknownQualifier qualifier ->
164+ "Cannot find " ++ var ++ "\n\n"
165+ ++ "The qualifier " ++ qualifier ++ " is not in scope."
166+ ++ maybeYouWant "\n" suggestions
168+ QualifiedUnknown qualifier ->
169+ "Cannot find " ++ var ++ "\n\n"
170+ ++ "The module called " ++ qualifier ++ " does not expose that value."
171+ ++ maybeYouWant "\n" suggestions
174+ "Cannot find " ++ var
175+ ++ maybeYouWant "\n\n" suggestions
177+ Pattern patternError ->
178+ case patternError of
179+ PatternArgMismatch var expected actual ->
180+ argMismatchHint "pattern" var expected actual
184+ ArgMismatch var expected actual ->
185+ argMismatchHint "type" var expected actual
187+ SelfRecursive name tvars tipe ->
188+ "This type alias is recursive, forming an infinite type!\n\n"
189+ ++ "Type aliases are just names for more fundamental types, so I go through\n"
190+ ++ "and expand them all to know the real underlying type. The problem is that\n"
191+ ++ "when I expand a recursive type alias, it keeps getting bigger and bigger.\n"
192+ ++ "Dealiasing results in an infinitely large type! Try this instead:\n\n"
193+ ++ " type " ++ name ++ concatMap (' ':) tvars ++ " ="
194+ ++ P.render (P.nest 8 (P.hang (P.text name) 2 (P.pretty True tipe)))
195+ ++ "\n\nThis creates a brand new type that cannot be expanded. It is similar types\n"
196+ ++ "like List which are recursive, but do not get expanded into infinite types."
198+ MutuallyRecursive aliases ->
199+ error "TODO" aliases
201+ Import name importError ->
203+ ModuleNotFound suggestions ->
204+ "Could not find a module named '" ++ Module.nameToString name ++ "'"
205+ ++ maybeYouWant "\n\n" (map Module.nameToString suggestions)
207+ ValueNotFound value suggestions ->
208+ "Module '" ++ Module.nameToString name ++ "' does not expose '" ++ value ++ "'"
209+ ++ maybeYouWant "\n\n" suggestions
211+ Export name suggestions ->
212+ "Could not export '" ++ name ++ "'\n\n"
213+ ++ "It is not defined in this module."
214+ ++ maybeYouWant " " suggestions
216+ Port (PortError name isInbound _rootType localType maybeMessage) ->
217+ "Cannot pass " ++ message ++ " through " ++ boundPort ++ " '" ++ name ++ "':\n\n"
218+ ++ P.render (P.nest 4 (P.pretty False localType)) ++ "\n\n"
219+ ++ "The kinds of values that can flow through " ++ boundPort ++ "s include:\n"
220+ ++ "Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples,\n"
221+ ++ "Json.Values, and concrete records."
224+ if isInbound then "inbound port" else "outbound port"
227+ maybe "the following type" id maybeMessage
230+argMismatchHint :: String -> Var.Canonical -> Int -> Int -> String
231+argMismatchHint kind var expected actual =
232+ "The " ++ kind ++ " " ++ Var.toString var ++ " has too "
233+ ++ (if actual < expected then "few" else "many")
235+ ++ "Expecting " ++ show expected ++ ", but got " ++ show actual
238+maybeYouWant :: String -> [String] -> String
239+maybeYouWant prefix suggestions =
246+ ++ "Maybe you want one of the following?\n"
247+ ++ concatMap ("\n "++) suggestions
147(.=.) key value =
251(.=.) key value =
148 key .= (value :: String)
252 key .= (value :: String)