on master help sign in
Better error messages for duplicate record fields

Also fix #1344 and detect duplicate fields in record update syntax

commit0d6c87f4806bde4ad3d221348c6d44daba9596d9 authorEvan Czaplicki <evancz@users.noreply.github.com> dateThu 24 Nov 2016, 13:41 (10 years ago) parentd17d9fe
6 files changed+38−29
src/AST/Expression/Source.hs+2−2 src/Canonicalize.hs+10−5 src/Parse/Expression.hs+5−5 src/Parse/Type.hs+1−1 src/Reporting/Error/Syntax.hs+4−3 src/Validate.hs+16−13
src/AST/Expression/Source.hs+2−2
@@ -36,8 +36,8 @@ data Expr' def
3636 | Case (Expr def) [(Ptrn.Raw, Expr def)]
3737 | Ctor String [Expr def]
3838 | Access (Expr def) String
39− | Update (Expr def) [(String, Expr def)]
40− | Record [(String, Expr def)]
39+ | Update (Expr def) [(A.Located String, Expr def)]
40+ | Record [(A.Located String, Expr def)]
4141 | GLShader String String Literal.GLShaderTipe
4242
4343
src/Canonicalize.hs+10−5
@@ -370,13 +370,10 @@ canonicalizeExpr env (A.A region validExpr) =
370370 C.Access <$> go record <*> Result.ok field
371371
372372 Src.Update record fields ->
373− C.Update
374− <$> go record
375− <*> traverse (\(field,expr) -> (,) field <$> go expr) fields
373+ C.Update <$> go record <*> traverse (canonicalizeFields env) fields
376374
377375 Src.Record fields ->
378− C.Record
379− <$> traverse (\(field,expr) -> (,) field <$> go expr) fields
376+ C.Record <$> traverse (canonicalizeFields env) fields
380377
381378 Src.Binop ops last ->
382379 canonicalizeBinop region env ops last
@@ -434,6 +431,14 @@ canonicalizeExpr env (A.A region validExpr) =
434431 Result.ok (C.GLShader uid src tipe)
435432
436433
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+
437442
438443-- PATTERNS
439444
src/Parse/Expression.hs+5−5
@@ -139,21 +139,21 @@ recordTerm =
139139 fields <- commaSep1 field
140140 return (Src.Update (A.A ann (Src.var starter)) fields)
141141
142− literal (A.A _ starter) =
142+ literal key =
143143 do try equals
144144 whitespace
145145 value <- expr
146146 whitespace
147147 choice
148− [ do try comma
148+ [ do comma
149149 whitespace
150150 fields <- commaSep field
151− return (Src.Record ((starter, value) : fields))
152− , return (Src.Record [(starter, value)])
151+ return (Src.Record ((key, value) : fields))
152+ , return (Src.Record [(key, value)])
153153 ]
154154
155155 field =
156− do key <- rLabel
156+ do key <- addLocation rLabel
157157 padded equals
158158 value <- expr
159159 return (key, value)
src/Parse/Type.hs+1−1
@@ -2,7 +2,7 @@
22module Parse.Type where
33
44import Data.List (intercalate)
5−import Text.Parsec ((<|>), (<?>), char, choice, many, optionMaybe, string, try)
5+import Text.Parsec ((<|>), (<?>), char, choice, optionMaybe, string, try)
66
77import qualified AST.Type as Type
88import qualified AST.Variable as Var
src/Reporting/Error/Syntax.hs+4−3
@@ -8,6 +8,7 @@ import Text.PrettyPrint.ANSI.Leijen (dullyellow, hsep, text)
88
99import qualified Reporting.Error.Helpers as Help
1010import qualified Reporting.Render.Type as RenderType
11+import qualified Reporting.Region as Region
1112import qualified Reporting.Report as Report
1213
1314
@@ -29,7 +30,7 @@ data Error
2930 | TypeWithoutDefinition String
3031
3132 | DuplicateArgument String String
32− | DuplicateFieldName String
33+ | DuplicateFieldName Region.Region String
3334 | DuplicateValueDeclaration String
3435 | DuplicateTypeDeclaration String
3536 | DuplicateDefinition String
@@ -188,10 +189,10 @@ toReport _localizer err =
188189 \ say `" ++ argName ++ "` it in the body of your function?"
189190 )
190191
191− DuplicateFieldName name ->
192+ DuplicateFieldName region name ->
192193 Report.report
193194 "DUPLICATE FIELD"
194− Nothing
195+ (Just region)
195196 ("This record has more than one field named `" ++ name ++ "`.")
196197 (text "There can only be one. Do some renaming to make sure the names are distinct!")
197198
src/Validate.hs+16−13
@@ -504,21 +504,12 @@ expression (A.A ann sourceExpression) =
504504 <*> return field
505505
506506 Src.Update record fields ->
507− Src.Update
508− <$> expression record
509− <*> traverse second fields
507+ do checkDuplicateFields ann fields
508+ Src.Update <$> expression record <*> traverse second fields
510509
511510 Src.Record fields ->
512− let
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
511+ do checkDuplicateFields ann fields
512+ Src.Record <$> traverse second fields
522513
523514 Src.Let defs body ->
524515 Src.Let
@@ -539,6 +530,18 @@ both (expr1, expr2) =
539530 (,) <$> expression expr1 <*> expression expr2
540531
541532
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+
542545
543546-- VALIDATE PATTERNS
544547