on master help sign in
Better error messages for function arguments

Specifically point out which argument is messed up (1st, 2nd, 3rd, etc) and say when too many arguments are given in a clearer way.

commitc0df14181140ba3ddf3e246ab00b50cc56ff02e5 authorEvan Czaplicki <info@elm-lang.org> dateThu 25 Jun 2015, 13:57 (11 years ago) parent0b499e6
2 files changed+140−36
src/Reporting/Error/Type.hs+55−16 src/Type/Constrain/Expression.hs+85−20
src/Reporting/Error/Type.hs+55−16
@@ -1,6 +1,7 @@
11{-# OPTIONS_GHC -Wall #-}
22module Reporting.Error.Type where
33
4+import qualified Data.Char as Char
45import Text.PrettyPrint ((<+>))
56import qualified Text.PrettyPrint as P
67
@@ -44,8 +45,9 @@ data Hint
4445 | BinopLeft Var.Canonical Region.Region
4546 | BinopRight Var.Canonical Region.Region
4647 | Binop Var.Canonical
47− | BadArgument Region.Region
48− | ExtraArgument Region.Region
48+ | Function (Maybe Var.Canonical)
49+ | UnexpectedArg (Maybe Var.Canonical) Int Region.Region
50+ | FunctionArity (Maybe Var.Canonical) Int Region.Region
4951 | BadTypeAnnotation String
5052 | Instance String
5153 | Literal String
@@ -53,7 +55,6 @@ data Hint
5355 | Shader
5456 | Range
5557 | Lambda
56− | App
5758 | Record
5859
5960
@@ -116,7 +117,7 @@ hintToString hint =
116117 CaseBranch branchNumber region ->
117118 ( Just region
118119 , "The branches of this case-expression return different types of values.\n\n"
119− ++ "I noticed the mismatch in branch #" ++ show branchNumber ++ ", but go through and make sure every\n"
120+ ++ "I noticed the mismatch in the " ++ ordinalize branchNumber ++ " branch, but go through and make sure every\n"
120121 ++ "branch returns the same type of value."
121122 )
122123
@@ -135,7 +136,7 @@ hintToString hint =
135136 MultiIfBranch branchNumber region ->
136137 ( Just region
137138 , "The branches of this if-expression return different types of values.\n\n"
138− ++ "I noticed the mismatch in branch #" ++ show branchNumber ++ ", but go through and make sure every\n"
139+ ++ "I noticed the mismatch in the " ++ ordinalize branchNumber ++ " branch, but go through and make sure every\n"
139140 ++ "branch returns the same type of value."
140141 )
141142
@@ -148,7 +149,7 @@ hintToString hint =
148149 ListElement elementNumber region ->
149150 ( Just region
150151 , "Not all elements of this list are the same type of value.\n\n"
151− ++ "I noticed the mismatch in element #" ++ show elementNumber ++ ", but go through and make sure every\n"
152+ ++ "I noticed the mismatch in the " ++ ordinalize elementNumber ++ " element, but go through and make sure every\n"
152153 ++ "element is the same type of value."
153154 )
154155
@@ -174,15 +175,21 @@ hintToString hint =
174175 ++ "does not match how it is used elsewhere."
175176 )
176177
177− BadArgument region ->
178+ Function maybeName ->
179+ ( Nothing
180+ , "The return type of " ++ funcName maybeName ++ " is being used in unexpected ways."
181+ )
182+
183+ UnexpectedArg maybeName index region ->
178184 ( Just region
179− , "This argument is causing a type mismatch."
185+ , "The " ++ ordinalize index ++ " argument to " ++ funcName maybeName
186+ ++ " has an unexpected type."
180187 )
181188
182− ExtraArgument region ->
189+ FunctionArity maybeName index region ->
183190 ( Just region
184− , "This expression is mistakenly being used as a function.\n"
185− ++ "Maybe you provided an extra argument?"
191+ , capitalize (funcName maybeName) ++ " is not expecting a "
192+ ++ ordinalize index ++ " argument."
186193 )
187194
188195 BadTypeAnnotation name ->
@@ -228,11 +235,6 @@ hintToString hint =
228235 , "This anonymous function is being used in an unexpected way."
229236 )
230237
231− App ->
232− ( Nothing
233− , "The result of this function application is being used in an unexpected way."
234− )
235−
236238 Record ->
237239 ( Nothing
238240 , "This record is being used in an unexpected way."
@@ -244,3 +246,40 @@ prettyOperator (Var.Canonical _ opName) =
244246 if Help.isOp opName
245247 then "(" ++ opName ++ ")"
246248 else "`" ++ opName ++ "`"
249+
250+
251+funcName :: Maybe Var.Canonical -> String
252+funcName maybeVar =
253+ case maybeVar of
254+ Nothing ->
255+ "this function"
256+
257+ Just var ->
258+ "function " ++ prettyOperator var
259+
260+
261+capitalize :: String -> String
262+capitalize string =
263+ case string of
264+ [] -> []
265+ c : cs ->
266+ Char.toUpper c : cs
267+
268+
269+ordinalize :: Int -> String
270+ordinalize number =
271+ let
272+ remainder10 =
273+ number `mod` 10
274+
275+ remainder100 =
276+ number `mod` 100
277+
278+ ending
279+ | remainder100 `elem` [11..13] = "th"
280+ | remainder10 == 1 = "st"
281+ | remainder10 == 2 = "nd"
282+ | remainder10 == 3 = "rd"
283+ | otherwise = "th"
284+ in
285+ show number ++ ending
src/Type/Constrain/Expression.hs+85−20
@@ -27,7 +27,7 @@ constrain
2727 -> Canonical.Expr
2828 -> Type
2929 -> IO TypeConstraint
30−constrain env (A.A region expression) tipe =
30+constrain env annotatedExpr@(A.A region expression) tipe =
3131 let list t = Env.get env Env.types "List" <| t
3232 (<?) = CInstance region
3333 in
@@ -91,25 +91,11 @@ constrain env (A.A region expression) tipe =
9191 )
9292 return $ con /\ CEqual Error.Lambda region tipe (argType ==> resType)
9393
94− E.App func@(A.A funcRegion _) arg@(A.A argRegion _) ->
95− do argVar <- variable Flexible
96− argCon <- constrain env arg (varN argVar)
97−
98− funcVar <- variable Flexible
99− funcCon <- constrain env func (varN funcVar)
100−
101− argVar' <- variable Flexible
102− resultVar <- variable Flexible
103−
104− return $ ex [funcVar, argVar, argVar', resultVar] $ CAnd $
105− [ argCon
106− , funcCon
107− , CEqual (Error.ExtraArgument funcRegion) region
108− (varN funcVar)
109− (varN argVar' ==> varN resultVar)
110− , CEqual (Error.BadArgument argRegion) region (varN argVar') (varN argVar)
111− , CEqual Error.App region tipe (varN resultVar)
112− ]
94+ E.App _ _ ->
95+ let
96+ (f:args) = E.collectApps annotatedExpr
97+ in
98+ constrainApp env region f args tipe
11399
114100 E.MultiIf branches ->
115101 constrainIf env region branches tipe
@@ -199,6 +185,85 @@ constrain env (A.A region expression) tipe =
199185 constrain env expr tipe
200186
201187
188+-- CONSTRAIN APP
189+
190+constrainApp
191+ :: Env.Environment
192+ -> R.Region
193+ -> Canonical.Expr
194+ -> [Canonical.Expr]
195+ -> Type
196+ -> IO TypeConstraint
197+constrainApp env region f args tipe =
198+ do funcVar <- variable Flexible
199+ funcCon <- constrain env f (varN funcVar)
200+
201+ (vars, numberOfArgsCons, argCons, argMatchCons, returnVar) <-
202+ argConstraints env maybeName region funcVar 1 args
203+
204+ let returnCon =
205+ CEqual (Error.Function maybeName) region (varN returnVar) tipe
206+
207+ return $ ex (funcVar : vars) $
208+ CAnd (funcCon : argCons ++ numberOfArgsCons ++ argMatchCons ++ [returnCon])
209+ where
210+ maybeName =
211+ case f of
212+ A.A _ (E.Var canonicalName) ->
213+ Just canonicalName
214+
215+ _ ->
216+ Nothing
217+
218+
219+argConstraints
220+ :: Env.Environment
221+ -> Maybe V.Canonical
222+ -> R.Region
223+ -> Variable
224+ -> Int
225+ -> [Canonical.Expr]
226+ -> IO ([Variable], [TypeConstraint], [TypeConstraint], [TypeConstraint], Variable)
227+argConstraints env name region overallVar index args =
228+ case args of
229+ [] ->
230+ return ([], [], [], [], overallVar)
231+
232+ expr@(A.A subregion _) : rest ->
233+ do argVar <- variable Flexible
234+ argCon <- constrain env expr (varN argVar)
235+
236+ argIndexVar <- variable Flexible
237+ localReturnVar <- variable Flexible
238+
239+ let numberOfArgsCon =
240+ CEqual
241+ (Error.FunctionArity name index subregion)
242+ region
243+ (varN argIndexVar ==> varN localReturnVar)
244+ (varN overallVar)
245+
246+ let argMatchCon =
247+ CEqual
248+ (Error.UnexpectedArg name index subregion)
249+ region
250+ (varN argIndexVar)
251+ (varN argVar)
252+
253+ (vars, numberOfArgsRest, argConRest, argMatchRest, returnVar) <-
254+ argConstraints env name region localReturnVar (index + 1) rest
255+
256+ return
257+ ( argVar : argIndexVar : localReturnVar : vars
258+ , numberOfArgsCon : numberOfArgsRest
259+ , argCon : argConRest
260+ , argMatchCon : argMatchRest
261+ , returnVar
262+ )
263+
264+
265+
266+
202267-- CONSTRAIN BINOP
203268
204269constrainBinop