Skip to content

Avoid parse error occurred when the field name generated by TH matches any of Haskell keywords#1476

Merged
parsonsmatt merged 6 commits intoyesodweb:masterfrom
ccycle:fix-mkRecordName
Mar 3, 2023
Merged

Avoid parse error occurred when the field name generated by TH matches any of Haskell keywords#1476
parsonsmatt merged 6 commits intoyesodweb:masterfrom
ccycle:fix-mkRecordName

Conversation

@ccycle
Copy link
Contributor

@ccycle ccycle commented Mar 2, 2023

To avoid the problem that GHC fails compiling due to parse error when the field name generated by Template Haskell matches any of Haskell keywords, this PR fixes mkRecordName to suffix _ if the field name matches any of keywords.

Before submitting your PR, check that you've:

  • Documented new APIs with Haddock markup
  • Added @since declarations to the Haddock
  • Ran stylish-haskell on any changed files.
  • Adhered to the code style (see the .editorconfig file for details)

After submitting your PR:

  • Update the Changelog.md file with a link to your PR
  • Bumped the version number if there isn't an (unreleased) on the Changelog
  • Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts)

Copy link
Collaborator

@parsonsmatt parsonsmatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing this up! One minor performance quibble.

At a future point, it would be nice to customize this behavior.

Since anyone writing type as a field name currently will receive GHC error, I think we can safely call this a bugfix. Mind doing a patch version bump and adding a changelog notice?

Comment on lines +3119 to +3127
avoidKeyword name = if name `elem` keywords then name ++ "_" else name

keywords :: [Text]
keywords =
["case","class","data","default","deriving","do","else"
,"if","import","in","infix","infixl","infixr","instance","let","module"
,"newtype","of","then","type","where","_"
,"foreign"
]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of list lookups like this is pretty inefficient - would prefer to see a Set lookup

Suggested change
avoidKeyword name = if name `elem` keywords then name ++ "_" else name
keywords :: [Text]
keywords =
["case","class","data","default","deriving","do","else"
,"if","import","in","infix","infixl","infixr","instance","let","module"
,"newtype","of","then","type","where","_"
,"foreign"
]
avoidKeyword name = if name `Set.member` haskellKeywords then name ++ "_" else name
haskellKeywords :: Set Text
haskellKeywords = Set.fromList
["case","class","data","default","deriving","do","else"
,"if","import","in","infix","infixl","infixr","instance","let","module"
,"newtype","of","then","type","where","_"
,"foreign"
]

Floating it to the top-level ensures we aren't constructing the Set for each call to mkRecordName, though I would guess GHC is capable of performing that optimization on it's own

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review, I changed the suggested part and added a notice to bump up a patch version in ChangeLog.

Copy link
Collaborator

@parsonsmatt parsonsmatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, thanks! I'll release this today.

@parsonsmatt parsonsmatt merged commit 23773f2 into yesodweb:master Mar 3, 2023
@ccycle ccycle deleted the fix-mkRecordName branch March 13, 2023 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants