on master help sign in
Give nicer errors for bad function defs and for duplicate variables in patterns

Fix #868

commit75ccf81a6d8f5c26103666885900d9d47c6d1dea authorEvan Czaplicki <info@elm-lang.org> dateMon 28 Sep 2015, 16:03 (11 years ago) parent5473c62
3 files changed+67−30
src/Parse/Expression.hs+6−24 src/Reporting/Error/Syntax.hs+22 src/Validate.hs+39−6
src/Parse/Expression.hs+6−24
@@ -296,7 +296,7 @@ definition :: IParser Source.Def
296296definition =
297297 addLocation $
298298 withPos $
299− do (name:args) <- defStart
299+ do (name, args) <- defStart
300300 padded equals
301301 body <- expr
302302 return . Source.Definition name $ makeFunction args body
@@ -307,27 +307,9 @@ makeFunction args body@(A.A ann _) =
307307 foldr (\arg body' -> A.A ann $ E.Lambda arg body') body args
308308
309309
310−defStart :: IParser [P.RawPattern]
310+defStart :: IParser (P.RawPattern, [P.RawPattern])
311311defStart =
312− choice
313− [ do pattern <- try Pattern.term
314− infics pattern <|> func pattern
315− , do opPattern <- addLocation (P.Var <$> parens symOp)
316− func opPattern
317− ]
318− <?> "the definition of a variable (x = ...)"
319− where
320− func pattern =
321− case pattern of
322− A.A _ (P.Var _) ->
323− (pattern:) <$> spacePrefix Pattern.term
324−
325− _ ->
326− return [pattern]
327−
328− infics p1 =
329− do (start, o:p, end) <- try (whitespace >> located anyOp)
330− p2 <- (whitespace >> Pattern.term)
331− let opName =
332− if o == '`' then takeWhile (/='`') p else o:p
333− return [ A.at start end (P.Var opName), p1, p2 ]
312+ expecting "the definition of a value (x = ...)" $
313+ do starter <- try Pattern.term <|> addLocation (P.Var <$> parens symOp)
314+ args <- spacePrefix Pattern.term
315+ return (starter, args)
src/Reporting/Error/Syntax.hs+22
@@ -15,6 +15,8 @@ import qualified Reporting.Report as Report
1515
1616data Error
1717 = Parse [Parsec.Message]
18+ | BadFunctionName Int
19+ | BadPattern String
1820 | InfixDuplicate String
1921 | TypeWithoutDefinition String
2022 | PortWithoutAnnotation String
@@ -34,6 +36,26 @@ toReport dealiaser err =
3436 Parse messages ->
3537 parseErrorReport messages
3638
39+ BadFunctionName arity ->
40+ Report.simple
41+ "BAD FUNCTION DEFINITION"
42+ "Complex patterns cannot be used as function names."
43+ ( "This function definition has " ++ show arity ++ " arguments, but instead of a normal name like\n"
44+ ++ "`add` or `reverse` it has a pattern. There is no way to \"deconstruct\" a\n"
45+ ++ "function with pattern matching, so this needs to be changed to a normal name."
46+ )
47+
48+ BadPattern name ->
49+ Report.simple
50+ "BAD PATTERN"
51+ ("The free variable `" ++ name ++ "` appears more than once in this pattern.")
52+ ( "Rename the variables so there are no duplicates.\n\n"
53+ ++ "In Elm, pattern matching works by binding these free variables to subsections\n"
54+ ++ "of the matching value. It does not make sense to have the same name for two\n"
55+ ++ "different subsections though! When you say `" ++ name ++ "` in some code, there\n"
56+ ++ "is no way for me to know which subsection you mean!"
57+ )
58+
3759 InfixDuplicate opName ->
3860 Report.simple
3961 "INFIX OVERLAP"
src/Validate.hs+39−6
@@ -7,7 +7,7 @@ import qualified Data.Set as Set
77import qualified Data.Foldable as F
88import qualified Data.Traversable as T
99
10−import AST.Expression.General
10+import AST.Expression.General as Expr
1111import qualified AST.Expression.Source as Source
1212import qualified AST.Expression.Valid as Valid
1313import qualified AST.Declaration as D
@@ -92,8 +92,9 @@ defHelp comment (A.A region def) decls =
9292 in
9393 case def of
9494 Source.Definition pat expr ->
95− do expr' <- Validate.expression expr
95+ do expr' <- expression expr
9696 let def' = Valid.Definition pat expr' Nothing
97+ checkDefinition def'
9798 addRest def' decls
9899
99100 Source.TypeAnnotation name tipe ->
@@ -101,8 +102,9 @@ defHelp comment (A.A region def) decls =
101102 D.Decl (A.A _ (D.Definition (A.A _
102103 (Source.Definition pat@(A.A _ (Pattern.Var name')) expr)))) : rest
103104 | name == name' ->
104− do expr' <- Validate.expression expr
105+ do expr' <- expression expr
105106 let def' = Valid.Definition pat expr' (Just tipe)
107+ checkDefinition def'
106108 addRest def' rest
107109
108110 _ ->
@@ -130,7 +132,7 @@ portHelp comment region port decls =
130132 case decls of
131133 D.Decl (A.A _ (D.Port (D.PortDefinition name' expr))) : rest
132134 | name == name' ->
133− do expr' <- Validate.expression expr
135+ do expr' <- expression expr
134136 let port' = D.Out name expr' tipe
135137 addRest port' rest
136138
@@ -157,6 +159,7 @@ definitionsHelp sourceDefs =
157159 A.A _ (Source.Definition pat expr) : rest ->
158160 do expr' <- expression expr
159161 let def = Valid.Definition pat expr' Nothing
162+ checkDefinition def
160163 (:) def <$> definitionsHelp rest
161164
162165 A.A region (Source.TypeAnnotation name tipe) : rest ->
@@ -165,12 +168,32 @@ definitionsHelp sourceDefs =
165168 | name == name' ->
166169 do expr' <- expression expr
167170 let def = Valid.Definition pat expr' (Just tipe)
171+ checkDefinition def
168172 (:) def <$> definitionsHelp rest'
169173
170174 _ ->
171175 Result.throw region (Error.TypeWithoutDefinition name)
172176
173177
178+checkDefinition :: Valid.Def -> Result.Result wrn Error.Error ()
179+checkDefinition (Valid.Definition pattern body _) =
180+ case fst (Expr.collectLambdas body) of
181+ [] ->
182+ return ()
183+
184+ args ->
185+ case pattern of
186+ A.A _ (Pattern.Var _) ->
187+ return ()
188+
189+ _ ->
190+ let
191+ (A.A start _) = pattern
192+ (A.A end _) = last args
193+ in
194+ Result.throw (R.merge start end) (Error.BadFunctionName (length args))
195+
196+
174197-- VALIDATE EXPRESSIONS
175198
176199expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
@@ -181,7 +204,9 @@ expression (A.A ann sourceExpression) =
181204 return (Var x)
182205
183206 Lambda pattern body ->
184− Lambda pattern <$> expression body
207+ Lambda
208+ <$> validatePattern pattern
209+ <*> expression body
185210
186211 Binop op leftExpr rightExpr ->
187212 Binop op
@@ -191,7 +216,7 @@ expression (A.A ann sourceExpression) =
191216 Case e branches ->
192217 Case
193218 <$> expression e
194− <*> T.traverse second branches
219+ <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
195220
196221 Data name args ->
197222 Data name <$> T.traverse expression args
@@ -267,6 +292,14 @@ both (expr1, expr2) =
267292 (,) <$> expression expr1 <*> expression expr2
268293
269294
295+-- VALIDATE PATTERNS
296+
297+validatePattern :: Pattern.RawPattern -> Result.Result wrn Error.Error Pattern.RawPattern
298+validatePattern pattern =
299+ do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
300+ return pattern
301+
302+
270303-- DETECT DUPLICATES
271304
272305detectDuplicates