New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Fix code generation for HKD records via plugin #34
Conversation
I tried this out in a large project and it's working for me. I think the change in this PR should be fine since there's a fundep |
This PR would fix #29. |
Put |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few little questions, but this looks very good. I note you've added this code to the plugin but NOT the preprocessor - is that deliberate? Do you think it can't work in the preprocessor? (If that's a divergence between the two, it will need documenting, as in most other ways they are equivalent)
plugin/RecordDotPreprocessor.hs
Outdated
|
||
|
||
makeEqQualTy :: HsType GhcPs -> (HsType GhcPs -> HsType GhcPs) -> HsType GhcPs | ||
makeEqQualTy rArg fAbs = let |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually prefer where over let like this - but I'm not too fussed.
plugin/RecordDotPreprocessor.hs
Outdated
instance' = ClsInstD noE $ ClsInstDecl noE (HsIB noE typ) (unitBag has) [] [] [] Nothing | ||
|
||
typ' a = mkHsAppTys | ||
(noL (HsTyVar noE GHC.NotPromoted (noL var_HasField))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we keep 4 space indents please.
@@ -228,3 +231,23 @@ adjacentBy i (L (srcSpanEnd -> RealSrcLoc a) _) (L (srcSpanStart -> RealSrcLoc b | |||
srcLocLine a == srcLocLine b && | |||
srcLocCol a + i == srcLocCol b | |||
adjacentBy _ _ _ = False | |||
|
|||
|
|||
makeEqQualTy :: HsType GhcPs -> (HsType GhcPs -> HsType GhcPs) -> HsType GhcPs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you include an example - e.g. Given t and f, it produces
t ~ f aplg` or whatever (its super hard to read these syntax productions in the abstract)
plugin/RecordDotPreprocessor.hs
Outdated
|
||
qualType :: HsType GhcPs | ||
qualType = HsQualTy noE (noL qualCtx) (noL (fAbs tyVar)) | ||
in qualType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we include a trailing newline for the while.
record-dot-preprocessor.cabal
Outdated
@@ -69,12 +69,14 @@ test-suite record-dot-preprocessor-test | |||
base == 4.*, | |||
extra, | |||
record-hasfield, | |||
filepath | |||
filepath, | |||
beam-core |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather avoid the beam dependency if we can. Are there no types in base
that let us express similar problems and will fail in similar ways?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is the result of a problem we had at @juspay internally, so right now references beam because it was the primary usecase — but if the approach seems good to you, the PR should definitely be polished and beam can be scrubbed out of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same re/ plugin vs preprocessor. Agreed that both should be implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I finisher preprocessor patching. But I have some problems with beam dependency removing. I have to add new library module with my own type family for testing. But as a result I have strange errors:
record-dot-preprocessor/utils/Utils.hs:1:1: error:
File name does not match module name:
Saw: ‘Main’
Expected: ‘Utils’
If someone have any idea how to add new module to this project structure, could you advice me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like you haven't written module Utils where
at the top of the module. I'd still encourage you to look for something pre-installed with base - Const
and WrappedMonad
might work: https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Applicative.html#t:Const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I tried with/without module name, but it doesn't work for now. I'll try more and write more specific question later :)
As about pre-installed base types - I don't think it is possible (probably I wrong) because the current version of the plugin should work well with constructions like
data MyData f = MyData {field :: f String}
instance HasField "field" (MyData f) (f String) where ...
Because there are no type families in the instance type
So we need some type family instead of C
from Beam, and it should be in a separate module for tests with qualified import. But, probably we can remove tests for qualified imports of C
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be tempted to just skip the qualified import tests - probably more hassle than they are worth. I think you do need the module header, but once you have that, I can imagine there are import path issues too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ndmitchell Well, I tried to make it as a lib few more times. It works well when I add a utility module with C type family to the plugin folder, because it is marked as library in cabal-file, I don't think it is correct approach. But I have problems when I tried to add it into tet folder, because of using system_ "runhaskell"
on it. So, I decided to inlne this test-type-family into Both.hs. Please take a lok at result. I think I finished all review fixes
record-dot-preprocessor.cabal
Outdated
if impl(ghc >= 8.6) | ||
build-depends: | ||
record-dot-preprocessor | ||
other-modules: | ||
PluginExample | ||
PluginHkdExample |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not add the plugin example to PluginExample
? Why a specific module for this one?
test/PluginExample.hs
Outdated
-- things that are now treated as comments | ||
{-# OPTIONS_GHC -Werror -Wall -Wno-type-defaults -Wno-partial-type-signatures -Wincomplete-record-updates -Wno-unused-top-binds #-} | ||
{-# OPTIONS_GHC -Wall -Wno-type-defaults -Wno-partial-type-signatures -Wincomplete-record-updates -Wno-unused-top-binds #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has ended up as a conflict. Can you rebase over master? Why remove the -Werror
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I had these problems with werror. I'll try to fix if it possible
record-dot-preprocessor/PluginExample:1:1: error: [-Wincomplete-record-updates, -Werror=incomplete-record-updates]
Pattern match(es) are non-exhaustive
In a record-update construct: Patterns not matched: (Foo8 _ _)
record-dot-preprocessor/PluginExample:1:1: error: [-Wincomplete-record-updates, -Werror=incomplete-record-updates]
Pattern match(es) are non-exhaustive
In a record-update construct: Patterns not matched: (Quux8 _)
record-dot-preprocessor/PluginExample:1:1: error: [-Wincomplete-record-updates, -Werror=incomplete-record-updates]
Pattern match(es) are non-exhaustive
In a record-update construct: Patterns not matched: (Quux8 _)
record-dot-preprocessor/PluginExample:1:1: error: [-Wincomplete-record-updates, -Werror=incomplete-record-updates]
Pattern match(es) are non-exhaustive
In a record-update construct: Patterns not matched: (Nonhuman _)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, it works after pulling from upstream master
And thanks very much for the patch, it does look great. |
So fundamentally, yes, this approach sounds great - just a question of getting the code into shape and will definitely want to land it! |
Looks perfect. Not sure what's happening to the CI reports, but Travis seems to think it ran, so lets err on the side of optimism and merge it: https://travis-ci.org/github/ndmitchell/record-dot-preprocessor/builds/731921087 Many thanks! Are you planning any more changes in the near future? If not, I'll make a release. |
Hang on, let us try it internally and report back |
But likely no further changes for now |
Cool, will await your confirmation then release. |
Could there be cases where this approach with the type equality constraint can lead to more complex error messages for simple cases? |
Let me know if you see worse error messages - internally GHC does approximately the same transformation when type checking, so I'm hopeful it will only be worse when you use the extra power. |
Looks good! Can release, I think |
Done and tweeted: https://twitter.com/ndm_haskell/status/1312008016183603201 Thanks for the patches! |
Should we mention somewhere in the readme that |
@pkapustin - seems reasonable - done in f6bba3b |
Also, in addition to |
@pkapustin is 23518a5 the change you think we need? |
@ndmitchell Yes, I think this is great. Maybe I would be even more specific and say that you either need |
@pkapustin if we had |
Currently we have a problem with records like this:
Because generated code looks like this:
It is impossible to have type family invocation in instance types
So, we moved this invocation into context and generate code like this:
And it works well, with UndecidableInstances