Can NamedFieldPuns be added to `GHC.LanguageExtensions.Types.Extension`?

Dear all, As some of you might know, for the past few months I have been working on changing GHC's diagnostic messages from plain SDocs to richer Haskell types. As part of this work, I have added a mechanism to embed hints into diagnostics, defined in `GHC.Types.Hint` in `HEAD`. One of the main workhorse of this `GhcHint` type is the `SuggestExtension LangExt.Extension` constructor, which embeds the extension to enable to use a particular feature. The `LangExt.Extension` type comes from `GHC.LanguageExtensions.Types`, and up until now there has always been a 1:1 mapping between the language pragma for the extension and the type itself. Today I was working on turning this error into a proper Haskell type: badPun :: Located RdrName -> TcRnMessage badPun fld = TcRnUnknownMessage $ mkPlainError noHints $ vcat [text "Illegal use of punning for field" <+> quotes (ppr fld), text "Use NamedFieldPuns to permit this"] I was ready to yield a `SuggestExtension LangExt.NamedFieldPuns` when I discovered that there is no `NamedFieldPuns` constructor. Rather, there is a `RecordPuns` , which refer to a deprecated flag, and we simply map `NamedFieldPuns` back to it in `GHC.Driver.Session`: ... depFlagSpec' "RecordPuns" LangExt.RecordPuns (deprecatedForExtension "NamedFieldPuns"), ... flagSpec "NamedFieldPuns" LangExt.RecordPuns, ... This is problematic for the `GhcHint` type, because now if I was to yield `SuggestExtension LangExt.RecordPuns` to the user, I could still pretty-print the suggestion to turn `RecordPuns` into `NamedFieldPuns`, but this means that IDEs or third-party library would have access to the "raw" Haskell datatype, and at that point they will be stuck with a suggestion to enable a deprecated extension! (or best case scenario they will have to transform the suggestion into something more sensible, which partially defeats the point of this refactoring work I have been doing). I am not sure this behaviour is unique for just `NamedFieldPuns`, but my question is: 1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume? Many thanks, Alfredo

1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
You mean, essentially, rename `LangExt.RecordPuns` to `NamedFieldPuns`.
I’d be fine with that. There might be back-compat issues, but only with other plugins, and probably with vanishingly few of them. Grep in Hackage!
Simon
From: ghc-devs

Hello Simon,
Yes, renaming and perhaps keeping `RecordPuns` as a pattern synonym to not
break backward-compat, if that's feasible to define as we are in
`ghc-boot-th` here. Not sure if `PatternSynonyms` and `COMPLETE` would be
available there.
I am not sure how many libs that depend on the ghc API would break (I
haven't grepped on Hackage yet), but that might tip the benefits/troubles
ratio towards keeping the status quo.
This is not a "problem" I have to solve today, and it might not be
considered a problem by others (just an inconsistency I guess): as a
colleague of mine pointed out, GHC is not necessarily "lying" here. It's
still the same underlying extension, it just happens that there are two
names that refer to it.
Perhaps I could think about adding to `GhcHint` some kind of mapping which
would give to IDEs or third-party libs the correct extension name given an
input `LangExt.Extension`, the problem then becomes making sure that we
keep this mapping in sync with the information contained in
`GHC.Driver.Session`.
I will let it simmer.
Thanks!
A.
On Tue, 6 Jul 2021 at 11:19, Simon Peyton Jones
1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
You mean, essentially, rename `LangExt.RecordPuns` to `NamedFieldPuns`.
I’d be fine with that. There might be back-compat issues, but only with other plugins, and probably with vanishingly few of them. Grep in Hackage!
Simon
*From:* ghc-devs
*On Behalf Of *Alfredo Di Napoli *Sent:* 06 July 2021 10:14 *To:* Simon Peyton Jones via ghc-devs *Subject:* Can NamedFieldPuns be added to `GHC.LanguageExtensions.Types.Extension`? Dear all,
As some of you might know, for the past few months I have been working on changing GHC's diagnostic messages from plain SDocs to richer Haskell types.
As part of this work, I have added a mechanism to embed hints into diagnostics, defined in `GHC.Types.Hint` in `HEAD`. One of the main workhorse of this `GhcHint` type is the `SuggestExtension LangExt.Extension` constructor, which embeds the extension to enable to use a particular feature. The `LangExt.Extension` type comes from `GHC.LanguageExtensions.Types`, and up until now there has always been a 1:1 mapping between the language pragma for the extension and the type itself.
Today I was working on turning this error into a proper Haskell type:
badPun :: Located RdrName -> TcRnMessage
badPun fld = TcRnUnknownMessage $ mkPlainError noHints $
vcat [text "Illegal use of punning for field" <+> quotes (ppr fld),
text "Use NamedFieldPuns to permit this"]
I was ready to yield a `SuggestExtension LangExt.NamedFieldPuns` when I discovered that there is no `NamedFieldPuns` constructor. Rather, there is a `RecordPuns` , which refer to a deprecated flag, and we simply map `NamedFieldPuns` back to it in `GHC.Driver.Session`:
...
depFlagSpec' "RecordPuns" LangExt.RecordPuns
(deprecatedForExtension "NamedFieldPuns"),
...
flagSpec "NamedFieldPuns" LangExt.RecordPuns,
...
This is problematic for the `GhcHint` type, because now if I was to yield `SuggestExtension LangExt.RecordPuns` to the user, I could still pretty-print the suggestion to turn `RecordPuns` into `NamedFieldPuns`, but this means that IDEs or third-party library would have access to the
"raw" Haskell datatype, and at that point they will be stuck with a suggestion to enable a deprecated extension! (or best case scenario they will have to transform the suggestion into something more sensible, which partially defeats the point of this refactoring work I have been doing).
I am not sure this behaviour is unique for just `NamedFieldPuns`, but my question is:
1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
Many thanks,
Alfredo

I think we just go ahead and rename the constructor. We don't have back-compat guarantees at this level. Simplicity is a virtue, too! Thanks, Richard
On Jul 6, 2021, at 5:59 AM, Alfredo Di Napoli
wrote: Hello Simon,
Yes, renaming and perhaps keeping `RecordPuns` as a pattern synonym to not break backward-compat, if that's feasible to define as we are in `ghc-boot-th` here. Not sure if `PatternSynonyms` and `COMPLETE` would be available there.
I am not sure how many libs that depend on the ghc API would break (I haven't grepped on Hackage yet), but that might tip the benefits/troubles ratio towards keeping the status quo.
This is not a "problem" I have to solve today, and it might not be considered a problem by others (just an inconsistency I guess): as a colleague of mine pointed out, GHC is not necessarily "lying" here. It's still the same underlying extension, it just happens that there are two names that refer to it.
Perhaps I could think about adding to `GhcHint` some kind of mapping which would give to IDEs or third-party libs the correct extension name given an input `LangExt.Extension`, the problem then becomes making sure that we keep this mapping in sync with the information contained in `GHC.Driver.Session`.
I will let it simmer.
Thanks!
A.
On Tue, 6 Jul 2021 at 11:19, Simon Peyton Jones
mailto:simonpj@microsoft.com> wrote: 1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume? You mean, essentially, rename `LangExt.RecordPuns` to `NamedFieldPuns`.
I’d be fine with that. There might be back-compat issues, but only with other plugins, and probably with vanishingly few of them. Grep in Hackage!
Simon
From: ghc-devs
mailto:ghc-devs-bounces@haskell.org> On Behalf Of Alfredo Di Napoli Sent: 06 July 2021 10:14 To: Simon Peyton Jones via ghc-devs mailto:ghc-devs@haskell.org> Subject: Can NamedFieldPuns be added to `GHC.LanguageExtensions.Types.Extension`? Dear all,
As some of you might know, for the past few months I have been working on changing GHC's diagnostic messages from plain SDocs to richer Haskell types.
As part of this work, I have added a mechanism to embed hints into diagnostics, defined in `GHC.Types.Hint` in `HEAD`. One of the main workhorse of this `GhcHint` type is the `SuggestExtension LangExt.Extension` constructor, which embeds the extension to enable to use a particular feature. The `LangExt.Extension` type comes from `GHC.LanguageExtensions.Types`, and up until now there has always been a 1:1 mapping between the language pragma for the extension and the type itself.
Today I was working on turning this error into a proper Haskell type:
badPun :: Located RdrName -> TcRnMessage
badPun fld = TcRnUnknownMessage $ mkPlainError noHints $
vcat [text "Illegal use of punning for field" <+> quotes (ppr fld),
text "Use NamedFieldPuns to permit this"]
I was ready to yield a `SuggestExtension LangExt.NamedFieldPuns` when I discovered that there is no `NamedFieldPuns` constructor. Rather, there is a `RecordPuns` , which refer to a deprecated flag, and we simply map `NamedFieldPuns` back to it in `GHC.Driver.Session`:
...
depFlagSpec' "RecordPuns" LangExt.RecordPuns
(deprecatedForExtension "NamedFieldPuns"),
...
flagSpec "NamedFieldPuns" LangExt.RecordPuns,
...
This is problematic for the `GhcHint` type, because now if I was to yield `SuggestExtension LangExt.RecordPuns` to the user, I could still pretty-print the suggestion to turn `RecordPuns` into `NamedFieldPuns`, but this means that IDEs or third-party library would have access to the
"raw" Haskell datatype, and at that point they will be stuck with a suggestion to enable a deprecated extension! (or best case scenario they will have to transform the suggestion into something more sensible, which partially defeats the point of this refactoring work I have been doing).
I am not sure this behaviour is unique for just `NamedFieldPuns`, but my question is:
1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
Many thanks,
Alfredo
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

There's always pattern synonyms as an option for cases like this, free of
backwards compat issues.
-Edward
On Tue, Jul 6, 2021 at 3:00 AM Alfredo Di Napoli
Hello Simon,
Yes, renaming and perhaps keeping `RecordPuns` as a pattern synonym to not break backward-compat, if that's feasible to define as we are in `ghc-boot-th` here. Not sure if `PatternSynonyms` and `COMPLETE` would be available there.
I am not sure how many libs that depend on the ghc API would break (I haven't grepped on Hackage yet), but that might tip the benefits/troubles ratio towards keeping the status quo.
This is not a "problem" I have to solve today, and it might not be considered a problem by others (just an inconsistency I guess): as a colleague of mine pointed out, GHC is not necessarily "lying" here. It's still the same underlying extension, it just happens that there are two names that refer to it.
Perhaps I could think about adding to `GhcHint` some kind of mapping which would give to IDEs or third-party libs the correct extension name given an input `LangExt.Extension`, the problem then becomes making sure that we keep this mapping in sync with the information contained in `GHC.Driver.Session`.
I will let it simmer.
Thanks!
A.
On Tue, 6 Jul 2021 at 11:19, Simon Peyton Jones
wrote: 1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
You mean, essentially, rename `LangExt.RecordPuns` to `NamedFieldPuns`.
I’d be fine with that. There might be back-compat issues, but only with other plugins, and probably with vanishingly few of them. Grep in Hackage!
Simon
*From:* ghc-devs
*On Behalf Of *Alfredo Di Napoli *Sent:* 06 July 2021 10:14 *To:* Simon Peyton Jones via ghc-devs *Subject:* Can NamedFieldPuns be added to `GHC.LanguageExtensions.Types.Extension`? Dear all,
As some of you might know, for the past few months I have been working on changing GHC's diagnostic messages from plain SDocs to richer Haskell types.
As part of this work, I have added a mechanism to embed hints into diagnostics, defined in `GHC.Types.Hint` in `HEAD`. One of the main workhorse of this `GhcHint` type is the `SuggestExtension LangExt.Extension` constructor, which embeds the extension to enable to use a particular feature. The `LangExt.Extension` type comes from `GHC.LanguageExtensions.Types`, and up until now there has always been a 1:1 mapping between the language pragma for the extension and the type itself.
Today I was working on turning this error into a proper Haskell type:
badPun :: Located RdrName -> TcRnMessage
badPun fld = TcRnUnknownMessage $ mkPlainError noHints $
vcat [text "Illegal use of punning for field" <+> quotes (ppr fld),
text "Use NamedFieldPuns to permit this"]
I was ready to yield a `SuggestExtension LangExt.NamedFieldPuns` when I discovered that there is no `NamedFieldPuns` constructor. Rather, there is a `RecordPuns` , which refer to a deprecated flag, and we simply map `NamedFieldPuns` back to it in `GHC.Driver.Session`:
...
depFlagSpec' "RecordPuns" LangExt.RecordPuns
(deprecatedForExtension "NamedFieldPuns"),
...
flagSpec "NamedFieldPuns" LangExt.RecordPuns,
...
This is problematic for the `GhcHint` type, because now if I was to yield `SuggestExtension LangExt.RecordPuns` to the user, I could still pretty-print the suggestion to turn `RecordPuns` into `NamedFieldPuns`, but this means that IDEs or third-party library would have access to the
"raw" Haskell datatype, and at that point they will be stuck with a suggestion to enable a deprecated extension! (or best case scenario they will have to transform the suggestion into something more sensible, which partially defeats the point of this refactoring work I have been doing).
I am not sure this behaviour is unique for just `NamedFieldPuns`, but my question is:
1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
Many thanks,
Alfredo
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Hello all,
I am happy to see engagement on this issue. I didn't read Ed's and
Richard's replies until now, but I have indeed explored the pattern synonym
solution, which I have materialised in a MR here:
https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6156
As I say in the MR description, the only small downside is the beefy
`COMPLETE` pragma, but we gain the possibility of deprecating the extension
a bit more explicitly, which is nice. Feedback welcome! :)
Thanks,
Alfredo
On Mon, 12 Jul 2021 at 17:08, Edward Kmett
There's always pattern synonyms as an option for cases like this, free of backwards compat issues.
-Edward
On Tue, Jul 6, 2021 at 3:00 AM Alfredo Di Napoli < alfredo.dinapoli@gmail.com> wrote:
Hello Simon,
Yes, renaming and perhaps keeping `RecordPuns` as a pattern synonym to not break backward-compat, if that's feasible to define as we are in `ghc-boot-th` here. Not sure if `PatternSynonyms` and `COMPLETE` would be available there.
I am not sure how many libs that depend on the ghc API would break (I haven't grepped on Hackage yet), but that might tip the benefits/troubles ratio towards keeping the status quo.
This is not a "problem" I have to solve today, and it might not be considered a problem by others (just an inconsistency I guess): as a colleague of mine pointed out, GHC is not necessarily "lying" here. It's still the same underlying extension, it just happens that there are two names that refer to it.
Perhaps I could think about adding to `GhcHint` some kind of mapping which would give to IDEs or third-party libs the correct extension name given an input `LangExt.Extension`, the problem then becomes making sure that we keep this mapping in sync with the information contained in `GHC.Driver.Session`.
I will let it simmer.
Thanks!
A.
On Tue, 6 Jul 2021 at 11:19, Simon Peyton Jones
wrote: 1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
You mean, essentially, rename `LangExt.RecordPuns` to `NamedFieldPuns`.
I’d be fine with that. There might be back-compat issues, but only with other plugins, and probably with vanishingly few of them. Grep in Hackage!
Simon
*From:* ghc-devs
*On Behalf Of *Alfredo Di Napoli *Sent:* 06 July 2021 10:14 *To:* Simon Peyton Jones via ghc-devs *Subject:* Can NamedFieldPuns be added to `GHC.LanguageExtensions.Types.Extension`? Dear all,
As some of you might know, for the past few months I have been working on changing GHC's diagnostic messages from plain SDocs to richer Haskell types.
As part of this work, I have added a mechanism to embed hints into diagnostics, defined in `GHC.Types.Hint` in `HEAD`. One of the main workhorse of this `GhcHint` type is the `SuggestExtension LangExt.Extension` constructor, which embeds the extension to enable to use a particular feature. The `LangExt.Extension` type comes from `GHC.LanguageExtensions.Types`, and up until now there has always been a 1:1 mapping between the language pragma for the extension and the type itself.
Today I was working on turning this error into a proper Haskell type:
badPun :: Located RdrName -> TcRnMessage
badPun fld = TcRnUnknownMessage $ mkPlainError noHints $
vcat [text "Illegal use of punning for field" <+> quotes (ppr fld),
text "Use NamedFieldPuns to permit this"]
I was ready to yield a `SuggestExtension LangExt.NamedFieldPuns` when I discovered that there is no `NamedFieldPuns` constructor. Rather, there is a `RecordPuns` , which refer to a deprecated flag, and we simply map `NamedFieldPuns` back to it in `GHC.Driver.Session`:
...
depFlagSpec' "RecordPuns" LangExt.RecordPuns
(deprecatedForExtension "NamedFieldPuns"),
...
flagSpec "NamedFieldPuns" LangExt.RecordPuns,
...
This is problematic for the `GhcHint` type, because now if I was to yield `SuggestExtension LangExt.RecordPuns` to the user, I could still pretty-print the suggestion to turn `RecordPuns` into `NamedFieldPuns`, but this means that IDEs or third-party library would have access to the
"raw" Haskell datatype, and at that point they will be stuck with a suggestion to enable a deprecated extension! (or best case scenario they will have to transform the suggestion into something more sensible, which partially defeats the point of this refactoring work I have been doing).
I am not sure this behaviour is unique for just `NamedFieldPuns`, but my question is:
1. What prevents us from adding `NamedFieldPuns` as a proper constructor for the `Extension` type and in principle remove `RecordPuns`? Backward compatibility I assume?
Many thanks,
Alfredo
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
participants (4)
-
Alfredo Di Napoli
-
Edward Kmett
-
Richard Eisenberg
-
Simon Peyton Jones