on master help sign in
Better error messages for duplicate record fields
0d6c87fEvan Czaplicki
src/AST/Expression/Source.hs+2−2
@@ -36,8 +36,8 @@ data Expr' def
36 | Case (Expr def) [(Ptrn.Raw, Expr def)]
36 | Case (Expr def) [(Ptrn.Raw, Expr def)]
37 | Ctor String [Expr def]
37 | Ctor String [Expr def]
38 | Access (Expr def) String
38 | Access (Expr def) String
39− | Update (Expr def) [(String, Expr def)]
39+ | Update (Expr def) [(A.Located String, Expr def)]
40− | Record [(String, Expr def)]
40+ | Record [(A.Located String, Expr def)]
41 | GLShader String String Literal.GLShaderTipe
41 | GLShader String String Literal.GLShaderTipe
42
42
43
43
src/Canonicalize.hs+10−5
@@ -370,13 +370,10 @@ canonicalizeExpr env (A.A region validExpr) =
370 C.Access <$> go record <*> Result.ok field
370 C.Access <$> go record <*> Result.ok field
371
371
372 Src.Update record fields ->
372 Src.Update record fields ->
373− C.Update
373+ C.Update <$> go record <*> traverse (canonicalizeFields env) fields
374− <$> go record
375− <*> traverse (\(field,expr) -> (,) field <$> go expr) fields
376
374
377 Src.Record fields ->
375 Src.Record fields ->
378− C.Record
376+ C.Record <$> traverse (canonicalizeFields env) fields
379− <$> traverse (\(field,expr) -> (,) field <$> go expr) fields
380
377
381 Src.Binop ops last ->
378 Src.Binop ops last ->
382 canonicalizeBinop region env ops last
379 canonicalizeBinop region env ops last
@@ -434,6 +431,14 @@ canonicalizeExpr env (A.A region validExpr) =
434 Result.ok (C.GLShader uid src tipe)
431 Result.ok (C.GLShader uid src tipe)
435
432
436
433
434+canonicalizeFields
435+ :: Env.Env
436+ -> (A.Located String, Src.ValidExpr)
437+ -> CResult (String, C.Expr)
438+canonicalizeFields env (A.A _ key, expr) =
439+ (\value -> (key, value)) <$> canonicalizeExpr env expr
440+
441+
437
442
438-- PATTERNS
443-- PATTERNS
439
444
src/Parse/Expression.hs+5−5
@@ -139,21 +139,21 @@ recordTerm =
139 fields <- commaSep1 field
139 fields <- commaSep1 field
140 return (Src.Update (A.A ann (Src.var starter)) fields)
140 return (Src.Update (A.A ann (Src.var starter)) fields)
141
141
142− literal (A.A _ starter) =
142+ literal key =
143 do try equals
143 do try equals
144 whitespace
144 whitespace
145 value <- expr
145 value <- expr
146 whitespace
146 whitespace
147 choice
147 choice
148− [ do try comma
148+ [ do comma
149 whitespace
149 whitespace
150 fields <- commaSep field
150 fields <- commaSep field
151− return (Src.Record ((starter, value) : fields))
151+ return (Src.Record ((key, value) : fields))
152− , return (Src.Record [(starter, value)])
152+ , return (Src.Record [(key, value)])
153 ]
153 ]
154
154
155 field =
155 field =
156− do key <- rLabel
156+ do key <- addLocation rLabel
157 padded equals
157 padded equals
158 value <- expr
158 value <- expr
159 return (key, value)
159 return (key, value)
src/Parse/Type.hs+1−1
@@ -2,7 +2,7 @@
2module Parse.Type where
2module Parse.Type where
3
3
4import Data.List (intercalate)
4import Data.List (intercalate)
5−import Text.Parsec ((<|>), (<?>), char, choice, many, optionMaybe, string, try)
5+import Text.Parsec ((<|>), (<?>), char, choice, optionMaybe, string, try)
6
6
7import qualified AST.Type as Type
7import qualified AST.Type as Type
8import qualified AST.Variable as Var
8import qualified AST.Variable as Var
src/Reporting/Error/Syntax.hs+4−3
@@ -8,6 +8,7 @@ import Text.PrettyPrint.ANSI.Leijen (dullyellow, hsep, text)
8
8
9import qualified Reporting.Error.Helpers as Help
9import qualified Reporting.Error.Helpers as Help
10import qualified Reporting.Render.Type as RenderType
10import qualified Reporting.Render.Type as RenderType
11+import qualified Reporting.Region as Region
11import qualified Reporting.Report as Report
12import qualified Reporting.Report as Report
12
13
13
14
@@ -29,7 +30,7 @@ data Error
29 | TypeWithoutDefinition String
30 | TypeWithoutDefinition String
30
31
31 | DuplicateArgument String String
32 | DuplicateArgument String String
32− | DuplicateFieldName String
33+ | DuplicateFieldName Region.Region String
33 | DuplicateValueDeclaration String
34 | DuplicateValueDeclaration String
34 | DuplicateTypeDeclaration String
35 | DuplicateTypeDeclaration String
35 | DuplicateDefinition String
36 | DuplicateDefinition String
@@ -188,10 +189,10 @@ toReport _localizer err =
188 \ say `" ++ argName ++ "` it in the body of your function?"
189 \ say `" ++ argName ++ "` it in the body of your function?"
189 )
190 )
190
191
191− DuplicateFieldName name ->
192+ DuplicateFieldName region name ->
192 Report.report
193 Report.report
193 "DUPLICATE FIELD"
194 "DUPLICATE FIELD"
194− Nothing
195+ (Just region)
195 ("This record has more than one field named `" ++ name ++ "`.")
196 ("This record has more than one field named `" ++ name ++ "`.")
196 (text "There can only be one. Do some renaming to make sure the names are distinct!")
197 (text "There can only be one. Do some renaming to make sure the names are distinct!")
197
198
src/Validate.hs+16−13
@@ -504,21 +504,12 @@ expression (A.A ann sourceExpression) =
504 <*> return field
504 <*> return field
505
505
506 Src.Update record fields ->
506 Src.Update record fields ->
507− Src.Update
507+ do checkDuplicateFields ann fields
508− <$> expression record
509− <*> traverse second fields
508+ Src.Update <$> expression record <*> traverse second fields
510
509
511 Src.Record fields ->
510 Src.Record fields ->
512− let
511+ do checkDuplicateFields ann fields
513− checkDups seenFields (field,_) =
514− if Set.member field seenFields then
515− Result.throw ann (Error.DuplicateFieldName field)
516−
517− else
518− return (Set.insert field seenFields)
519− in
520− do foldM_ checkDups Set.empty fields
521− Src.Record <$> traverse second fields
512+ Src.Record <$> traverse second fields
522
513
523 Src.Let defs body ->
514 Src.Let defs body ->
524 Src.Let
515 Src.Let
@@ -539,6 +530,18 @@ both (expr1, expr2) =
539 (,) <$> expression expr1 <*> expression expr2
530 (,) <$> expression expr1 <*> expression expr2
540
531
541
532
533+checkDuplicateFields :: R.Region -> [(A.Located String, a)] -> Result wrn ()
534+checkDuplicateFields recordRegion fields =
535+ let
536+ checkDups seenFields ( A.A region field, _ ) =
537+ if Set.member field seenFields then
538+ Result.throw recordRegion (Error.DuplicateFieldName region field)
539+ else
540+ Result.ok (Set.insert field seenFields)
541+ in
542+ foldM_ checkDups Set.empty fields
543+
544+
542
545
543-- VALIDATE PATTERNS
546-- VALIDATE PATTERNS
544
547