@@ -8,11 +8,13 @@ import qualified Data.Aeson as Json
88import Data.Function (on)
99import qualified Data.List as List
1010import qualified Text.EditDistance as Dist
11+import qualified Text.PrettyPrint as P
1112
1213import qualified AST.Module as Module
1314import qualified AST.Type as Type
1415import qualified AST.Variable as Var
1516import Elm.Utils ((|>))
17+import qualified Reporting.PrettyPrint as P
1618import qualified Reporting.Region as R
1719
1820
@@ -31,19 +33,20 @@ data VarError = VarError
3133 { varKind :: String
3234 , varName :: String
3335 , varProblem :: VarProblem
36+ , varSuggestions :: [String]
3437 }
3538
3639
3740data VarProblem
38− = Ambiguous [String]
39− | UnknownQualifier [Module.Name]
40− | QualifiedUnknown [String]
41− | ExposedUnknown { closeExposed :: [String], closeQualified :: [String] }
41+ = Ambiguous
42+ | UnknownQualifier String
43+ | QualifiedUnknown String
44+ | ExposedUnknown
4245
4346
44−var :: String -> String -> VarProblem -> Error
45−var kind name problem =
46− Var (VarError kind name problem)
47+variable :: String -> String -> VarProblem -> [String] -> Error
48+variable kind name problem suggestions =
49+ Var (VarError kind name problem suggestions)
4750
4851
4952-- PATTERN
@@ -94,7 +97,7 @@ data PortError = PortError
9497 , portIsInbound :: Bool
9598 , portRootType :: Type.Canonical
9699 , portLocalType :: Type.Canonical
97− , portMessage :: String
100+ , portMessage :: Maybe String
98101 }
99102
100103
@@ -103,10 +106,10 @@ port
103106 -> Bool
104107 -> Type.Canonical
105108 -> Type.Canonical
106− -> String
109+ -> Maybe String
107110 -> Error
108−port name isInbound rootType localType message =
109− Port (PortError name isInbound rootType localType message)
111+port name isInbound rootType localType maybeMessage =
112+ Port (PortError name isInbound rootType localType maybeMessage)
110113
111114
112115-- NEARBY NAMES
@@ -143,6 +146,107 @@ toJson err =
143146 case err of
144147 _ -> error "Canonicalize.toJson"
145148
149+
150+-- HINTS
151+
152+toHint :: Error -> String
153+toHint err =
154+ case err of
155+ Var (VarError kind name problem suggestions) ->
156+ let var = kind ++ "'" ++ name ++ "'"
157+ in
158+ case problem of
159+ Ambiguous ->
160+ "This usage of " ++ var ++ " is ambiguous"
161+ ++ maybeYouWant "\n\n" suggestions
162+
163+ UnknownQualifier qualifier ->
164+ "Cannot find " ++ var ++ "\n\n"
165+ ++ "The qualifier " ++ qualifier ++ " is not in scope."
166+ ++ maybeYouWant "\n" suggestions
167+
168+ QualifiedUnknown qualifier ->
169+ "Cannot find " ++ var ++ "\n\n"
170+ ++ "The module called " ++ qualifier ++ " does not expose that value."
171+ ++ maybeYouWant "\n" suggestions
172+
173+ ExposedUnknown ->
174+ "Cannot find " ++ var
175+ ++ maybeYouWant "\n\n" suggestions
176+
177+ Pattern patternError ->
178+ case patternError of
179+ PatternArgMismatch var expected actual ->
180+ argMismatchHint "pattern" var expected actual
181+
182+ Alias aliasError ->
183+ case aliasError of
184+ ArgMismatch var expected actual ->
185+ argMismatchHint "type" var expected actual
186+
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."
197+
198+ MutuallyRecursive aliases ->
199+ error "TODO" aliases
200+
201+ Import name importError ->
202+ case importError of
203+ ModuleNotFound suggestions ->
204+ "Could not find a module named '" ++ Module.nameToString name ++ "'"
205+ ++ maybeYouWant "\n\n" (map Module.nameToString suggestions)
206+
207+ ValueNotFound value suggestions ->
208+ "Module '" ++ Module.nameToString name ++ "' does not expose '" ++ value ++ "'"
209+ ++ maybeYouWant "\n\n" suggestions
210+
211+ Export name suggestions ->
212+ "Could not export '" ++ name ++ "'\n\n"
213+ ++ "It is not defined in this module."
214+ ++ maybeYouWant " " suggestions
215+
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."
222+ where
223+ boundPort =
224+ if isInbound then "inbound port" else "outbound port"
225+
226+ message =
227+ maybe "the following type" id maybeMessage
228+
229+
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")
234+ ++ "arguments.\n\n"
235+ ++ "Expecting " ++ show expected ++ ", but got " ++ show actual
236+
237+
238+maybeYouWant :: String -> [String] -> String
239+maybeYouWant prefix suggestions =
240+ case suggestions of
241+ [] ->
242+ ""
243+
244+ _:_ ->
245+ prefix
246+ ++ "Maybe you want one of the following?\n"
247+ ++ concatMap ("\n "++) suggestions
248+
249+
146250{--
147251(.=.) key value =
148252 key .= (value :: String)