GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2024-01-19T15:09:10Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/18776Improve "No instance for HasField" error messages2024-01-19T15:09:10ZAdam GundryImprove "No instance for HasField" error messagesThe built-in `HasField x r a` constraint is solved automatically whenever `x` is a field label that belongs to the type `r` (except if the field is not in scope, or for a few other corner cases, e.g. the field type is existential, higher...The built-in `HasField x r a` constraint is solved automatically whenever `x` is a field label that belongs to the type `r` (except if the field is not in scope, or for a few other corner cases, e.g. the field type is existential, higher-rank or unboxed). If it is not solved automatically, however, the error message is typically just
```
No instance for (HasField "foo" T ()) arising from ...
```
which is rather uninformative. It would be better to customise the error reporting:
* If the type `r` is not a record type at all, we could mention that fact.
* If the type `r` is a record type, but does not have the named field, we could suggest similarly-named fields (like how the renamer suggests possibilities for not-in-scope identifiers).
* If the field does belong to the type, but is not in scope, we could say that and suggest importing it.
* If the field type is existential, higher-rank or unboxed, we could explain that such fields cannot be used with `HasField`.https://gitlab.haskell.org/ghc/ghc/-/issues/17834Support RecordWildCards in HPC2020-06-29T20:59:20ZBrandon ChinnSupport RecordWildCards in HPC## Summary
Data type records are marked as "never executed" when I use them only with RecordWildCards. The same could probably be said for NamedFieldPuns as well.
## Steps to reproduce
```haskell
{-# LANGUAGE RecordWildCards #-}
data...## Summary
Data type records are marked as "never executed" when I use them only with RecordWildCards. The same could probably be said for NamedFieldPuns as well.
## Steps to reproduce
```haskell
{-# LANGUAGE RecordWildCards #-}
data Foo = Foo
{ foo1 :: Int
, foo2 :: Int
}
showFoo :: Foo -> IO ()
showFoo Foo{..} = print (foo1, foo2)
main = showFoo (Foo 1 2)
```
Running the above with coverage shows `foo1` and `foo2` as uncovered.
[Main.hs](/uploads/1c2bf48faab46d8da7a7cc10bd50aaae/Main.hs)
[Main.hs.html](/uploads/da8184b460bc0d399de6f498997191ab/Main.hs.html)
## Expected behavior
`foo1` and `foo2` should be marked as "hit"
## Environment
* GHC version used: 8.8.1
Optional:
* Operating System: MacOS 10.14.6
* System Architecture:https://gitlab.haskell.org/ghc/ghc/-/issues/22384Visible type application in record patterns2022-11-01T08:49:22ZTarmeanVisible type application in record patterns## Motivation
I've been using type applications in patterns quite a bit recently and struggled when adding or removing an argument from the constructors because all pattern matches must add/remove wildcards.
```haskell
lookupQMap :: fo...## Motivation
I've been using type applications in patterns quite a bit recently and struggled when adding or removing an argument from the constructors because all pattern matches must add/remove wildcards.
```haskell
lookupQMap :: forall a. Typeable a => QKey a -> QMap -> Maybe a
lookupQMap qid qmap =
-- This could use a Data.Typeable.cast, but it's simplified from some more complex code
case lookupQ qid qmap of
ResultEntry @r' dat _
| Just Refl <- eqT @r @r' -> ...
```
The nice way to avoid the problem would be to use record patterns. But mixing type applications with record patterns results in a parse error!
```haskell
case lookupQ qid qmap of
ResultEntry @r {resultData=dat}
-- [parser] [E] parser error on input '{'
```
I'm not sure if this is intentional, an oversight, or whether I'm missing the right syntax. It'd be really useful, though!
## Proposal
If the missing syntax is an oversight it hopefully could be added without making the grammar overly ambiguous. I do not know whether this would require a separate proposal.
If the feature already exists or is intentionally missing it maybe could be documented somewhere, though I'm not sure what the right place would be. I couldn't find a mention in the proposal or paper at least.https://gitlab.haskell.org/ghc/ghc/-/issues/23535Chunkify large records similar to large tuples2023-06-20T15:07:55ZAlex McKennaChunkify large records similar to large tuples## Motivation
During a conversation at ZuriHac, the problem of inefficiency when using large records came up (for a good write up of this problem, see [this blog post from Well Typed](https://well-typed.com/blog/2021/08/large-records/))...## Motivation
During a conversation at ZuriHac, the problem of inefficiency when using large records came up (for a good write up of this problem, see [this blog post from Well Typed](https://well-typed.com/blog/2021/08/large-records/)). Towards the end of the blog post some concerns / ideas are raised:
- The solution in the blog post involves using a library, it is not a solution baked into GHC
- It may be possible to alleviate the problem with more sharing (see https://gitlab.haskell.org/ghc/ghc/-/issues/20264)
- Record pattern matches are still linear in the size of the record
## Proposal
Thinking out loud I asked Simon whether we could do something similar to the treatment of large tuples, and have GHC keep a representation internally that was more nested.[^1] Simon enthusiastically raised some points, which I will attempt to faithfully relay here:
- We have machinery in the compiler for specifying a more efficient internal representation for data, `mkDataConRep` etc.
- We already go the other way in GHC and expand records (e.g. using `{-# UNPACK #-}` on a strict tuple field)
- Using a chunked representation means selector functions become a case tree
- Record updates can share chunks of a record which are not changed
To give some examples (in deliberately invalid Haskell): a large record
```
{ x0 :: A0, ..., xn :: An }
```
would be internally represented as something similar to
```
{ { x0 :: A0, ..., xK-1 :: AK-1 }, { xK :: AK, ... }, { ..., xn :: An } }
```
where each chunk has K number of fields. The selector functions change accordingly
```
sel_xn_old r =
case r of
C0 _ ... xn -> xn -- Pattern linear to number of fields
sel_xn_new r =
case r of
C1 _ c1 -> -- Each item here is just a chunk
case c1 of
C2 _ ... xn -> xn -- Match on chunks until we find the element we want
```
Thinking about this the past week or so I have some more questions about this:
- How would `{-# UNPACK #-}` play nicely with a chunked record representation? We do not have to think about this for tuples because it is not valid to write something like `(Int, {-# UNPACK #-} !Int)` in Haskell. Intuitively, I would guess that such strict unpacked fields would be floated to the top of the record alongside the chunks.
- Would we generate new types for the chunks, or use tuples internally to represent the chunks. I feel like tuples would be simpler, but perhaps there is some reason to not favour this?
[^1]: Due to a limit set by the format of info tables, GHC only allows tuples of up to 64 elements internally. However, when writing code in the surface syntax of Haskell, we can use tuples larger than 64. Internally, GHC splits the tuple into a tuple of smaller tuples which can contain all the elements. This is transparent to the user writing the code.
---
@simonpj As promised, I have written this up as an issue. Hopefully this is clear enough starting point for people to discuss.https://gitlab.haskell.org/ghc/ghc/-/issues/21324HasField instances cannot be defined on newtypes that have a field selector e...2022-06-12T06:54:36ZOllie CharlesHasField instances cannot be defined on newtypes that have a field selector even if that isn't exported## Motivation
I would like to able to provide a `HasField` instance for `reactive-banana` [`Behavior`](https://hackage.haskell.org/package/reactive-banana-1.3.0.0/docs/Reactive-Banana-Combinators.html#t:Behavior)s. Specifically, I want ...## Motivation
I would like to able to provide a `HasField` instance for `reactive-banana` [`Behavior`](https://hackage.haskell.org/package/reactive-banana-1.3.0.0/docs/Reactive-Banana-Combinators.html#t:Behavior)s. Specifically, I want to write
```haskell
instance HasField x a b => HasField (x :: Symbol) (Behavior a) (Behavior b) where
getField behavior = behavior <&> getField @x
```
Unfortunately, GHC refuses to allow me to write this, reporting:
```
lib/Reactive/Banana/Orphans.hs:36:28: error:
• Illegal instance declaration for
‘HasField x (Behavior a) (Behavior b)’
Behavior has fields
• In the instance declaration for
‘HasField (x :: Symbol) (Behavior a) (Behavior b)’
|
36 | instance HasField x a b => HasField (x :: Symbol) (Behavior a) (Behavior b) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
but I disagree that `Behavior` has fields. *Internally* `Behavior` is defined as
```haskell
newtype Behavior a = B { unB :: Prim.Behavior a }
```
but that is never exported - no module expect the defining one can see that field.
## Proposal
I am able to write the instance.https://gitlab.haskell.org/ghc/ghc/-/issues/19461Remove AmbiguousFieldOcc2023-09-21T07:10:31ZAdam GundryRemove AmbiguousFieldOccUnder [ghc-proposals#366](https://github.com/ghc-proposals/ghc-proposals/pull/366) we are deprecating the special typechecker-assisted name resolution that `DuplicateRecordFields` uses for "ambiguous" selectors and updates. In GHC 9.2, a...Under [ghc-proposals#366](https://github.com/ghc-proposals/ghc-proposals/pull/366) we are deprecating the special typechecker-assisted name resolution that `DuplicateRecordFields` uses for "ambiguous" selectors and updates. In GHC 9.2, a new warning `-Wambiguous-fields` will give users advance warning of this change (#18966, !4770).
Under the proposal, a subsequent GHC release will remove support entirely. This will allow us to remove `AmbiguousFieldOcc` from the codebase and make consequent simplifications. This ticket is to track this cleanup.Adam GundryAdam Gundryhttps://gitlab.haskell.org/ghc/ghc/-/issues/18869Include field type in missing field error message2021-01-18T12:48:39ZparsonsmattInclude field type in missing field error message## Motivation
I'm working on some code that hasn't been touched in a while (*cough* test suite *cough), and a lot of types have been updated with new fields and changed fields. So all of the record creation stuff needs addressing.
An e...## Motivation
I'm working on some code that hasn't been touched in a while (*cough* test suite *cough), and a lot of types have been updated with new fields and changed fields. So all of the record creation stuff needs addressing.
An example error message is:
```
lumi-mojo > /home/matt/Projects/lumi/mojo/common/test/Lumi/Gen/Schema/Quote.hs:85:20: error:
lumi-mojo > • Constructor ‘QuoteVariant’ does not have the required strict field(s): quoteVariantCloneDescription
lumi-mojo > • In the expression:
lumi-mojo > QuoteVariant
```
So I'll throw in the line:
```diff
, quoteVariantThing = Nothing
+ , quoteVariantCloneDescription = ""
}
```
But this isn't right! `quoteVariantCloneDescription` has the type `Maybe Text`. So I need to go through and do another edit:
```diff
, quoteVariantThing = Nothing
- , quoteVariantCloneDescription = ""
+ , quoteVariantCloneDescription = Nothing
}
```
## Proposal
This minor inconvenience can easily be fixed by supplying the type of the missing field.
```diff
/home/matt/Projects/lumi/mojo/common/test/Lumi/Gen/Schema/Quote.hs:85:20: error:
- • Constructor ‘QuoteVariant’ does not have the required strict field(s): quoteVariantCloneDescription
+ • Constructor ‘QuoteVariant’ does not have the required strict field(s): quoteVariantCloneDescription :: Maybe Text
• In the expression:
QuoteVariant
```https://gitlab.haskell.org/ghc/ghc/-/issues/13307Record pattern synonym fields have to be manually exported2023-09-18T06:54:00ZOllie CharlesRecord pattern synonym fields have to be manually exportedThe following currently fails to compile:
```hs
{-# LANGUAGE PatternSynonyms #-}
module A( T( MkT2 ) ) where
data Impl = Impl Int
newtype T = MkT Impl
pattern MkT2 {x} = MkT (Impl x)
{-# LANGUAGE RecordWildCards #-}
module B where
...The following currently fails to compile:
```hs
{-# LANGUAGE PatternSynonyms #-}
module A( T( MkT2 ) ) where
data Impl = Impl Int
newtype T = MkT Impl
pattern MkT2 {x} = MkT (Impl x)
{-# LANGUAGE RecordWildCards #-}
module B where
import A
foo :: T -> Int
foo MkT2{x} = x
```
As far as GHC can see, in module `B`, `MkT2` does not have a field `x`. The fix is to manually export `x` from `A`:
```hs
module A (T(MkT2, x)) where
```
But this is tedious for records with a large amount of fieldshttps://gitlab.haskell.org/ghc/ghc/-/issues/24483Can't re-export duplicate field names from identical constructor names2024-02-27T15:47:53ZTom EllisCan't re-export duplicate field names from identical constructor namesThis is a new ticket to track [an issue explained by @adamgundry](https://gitlab.haskell.org/ghc/ghc/-/issues/13352#note_294968) in a prior (closed) ticket. That is, the following code leads to the following error. The error is still pr...This is a new ticket to track [an issue explained by @adamgundry](https://gitlab.haskell.org/ghc/ghc/-/issues/13352#note_294968) in a prior (closed) ticket. That is, the following code leads to the following error. The error is still present as of GHC 9.8. It seems like an artificial limitation and it would be great if it could be lifted. This is particularly annoying if we want to create a custom `Prelude`. It makes it impossible to create a custom `Prelude` containing two different fields with the same name, if their constructors also share the same name.
```
{-# LANGUAGE DuplicateRecordFields #-}
module A where
data S = C { foo :: Int }
{-# LANGUAGE DuplicateRecordFields #-}
module B where
data T = C { foo :: Int }
{-# LANGUAGE DuplicateRecordFields #-}
module C (S(foo), T(foo)) where
import A (S(..))
import B (T(..))
```
```
Conflicting exports for ‘foo’:
‘S(foo)’ exports ‘foo’
imported from ‘A’ at C.hs:5:28-32
(and originally defined at A.hs:3:16-18)
‘T(foo)’ exports ‘foo’
imported from ‘B’ at C.hs:6:28-32
(and originally defined at B.hs:5:14-16)
```
----
It's also an interesting puzzle to try to imagine the implementation details that allow both `foo`s to be used within the same module but not re-exported from the same module! I haven't been able to work it out ...
EDIT: Ah, I think I have an explanation: in a given module, duplicate field names are disambiguated by the module they were imported from plus the constructor name.https://gitlab.haskell.org/ghc/ghc/-/issues/24481Support NoFieldSelectors as a datatype and field annotation2024-02-26T09:45:21ZAdam GundrySupport NoFieldSelectors as a datatype and field annotationThe GHC Steering Committee has accepted [proposal 512: NoFieldSelectors as a datatype and field annotation](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0512-nofieldselectors-per-datatype.md). This makes it possib...The GHC Steering Committee has accepted [proposal 512: NoFieldSelectors as a datatype and field annotation](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0512-nofieldselectors-per-datatype.md). This makes it possible to annotate individual datatypes or fields as to whether they should use `FieldSelectors` or `NoFieldSelectors`.https://gitlab.haskell.org/ghc/ghc/-/issues/24330hpc complains that record field referencing an existential is never executed2024-01-23T14:31:17ZShea Levyshea@shealevy.comhpc complains that record field referencing an existential is never executed## Summary
```haskell
{-# LANGUAGE ExistentialQuantification #-}
module Main where
data Any = forall a. Any { any :: a }
main :: IO ()
main = do
let x = Any 'c'
case x of
Any _ -> pure ()
```
![image](/uploads/f561b311655ef76...## Summary
```haskell
{-# LANGUAGE ExistentialQuantification #-}
module Main where
data Any = forall a. Any { any :: a }
main :: IO ()
main = do
let x = Any 'c'
case x of
Any _ -> pure ()
```
![image](/uploads/f561b311655ef76e403e6a69bfcce000/image.png)
## Steps to reproduce
`ghc -fhpc Test.hs && ./Test && hpc report Test`
## Expected behavior
`any` is not marked up as `never executed`, as there is no way to call it
## Environment
* GHC version used: 9.2.4, 9.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/24174OverloadedRecordDot: "type" can't be used as a field name2023-11-15T04:02:22ZHaisheng, WuOverloadedRecordDot: "type" can't be used as a field name## Summary
* I cannot use "type" as a field name.
* Looks like same problem as #21226 #20723 but looks like it didn't fix the problem for all others reserved keywords in `reservedid`
## Steps to reproduce
Given following code:
```has...## Summary
* I cannot use "type" as a field name.
* Looks like same problem as #21226 #20723 but looks like it didn't fix the problem for all others reserved keywords in `reservedid`
## Steps to reproduce
Given following code:
```haskell
{-# LANGUAGE OverloadedRecordDot, DataKinds #-}
module Main where
import GHC.Records ( HasField(..) )
data Product = Product
{ prodName :: String
, prodType :: String
}
sampleProduct :: Product
sampleProduct = Product "Foo" "Sport"
instance HasField "type" Product String where
getField :: Product -> String
getField = prodType
main :: IO ()
main = putStrLn sampleProduct.type
```
I got compilation error:
```plaintext
[1 of 2] Compiling Main ( main.hs, main.o ) [Source file changed]
main.hs:19:31: error: [GHC-58481] parse error on input ‘type’
|
19 | main = putStrLn sampleProduct.type
```
## Expected behavior
Compile and run successfully.
## Environment
* GHC version used: 9.6.3
Optional:
* Operating System: MacOS-14.4
* System Architecture:https://gitlab.haskell.org/ghc/ghc/-/issues/24097GADT record syntax does not accept linearity annotations2023-10-16T08:12:11ZRodrigo MesquitaGADT record syntax does not accept linearity annotationsIn #19928 @int-index dropped the parser's support for GADT record syntax with multiplicity annotations, since the annotations were not respected. For instance:
```haskell
{-# LANGUAGE UnicodeSyntax, LinearTypes #-}
module M where
data...In #19928 @int-index dropped the parser's support for GADT record syntax with multiplicity annotations, since the annotations were not respected. For instance:
```haskell
{-# LANGUAGE UnicodeSyntax, LinearTypes #-}
module M where
data R where
D1 :: { d1 :: Int, d1' :: Int } %1 -> R
DUr :: { dur :: Int, dur' :: Int } -> R
```
Is rejected with a parser error.
However, I was writing a program in which I made use of the syntax as in `D1`, expecting to make both `d1` and `d1'` linear fields.
On the other hand, I would expect `dur` and `dur'` to be an unrestricted field.
I suppose I'm treading on undefined behaviour, but I think it is intuitive for linearity annotations to work in this way for GADT record syntax.
Discussion welcome!https://gitlab.haskell.org/ghc/ghc/-/issues/24035incorrect `-Wunused-imports` when module exports multiple records with the sa...2023-10-03T14:13:43ZMagnus Viernickelincorrect `-Wunused-imports` when module exports multiple records with the same accessor names## Summary
GHC emits unused imports warnings when the module that is imported from has `DuplicatRecordFields` activated and exports Records with same acessor fields
## Steps to reproduce
```hs
{-# LANGUAGE DuplicateRecordFields #-}
...## Summary
GHC emits unused imports warnings when the module that is imported from has `DuplicatRecordFields` activated and exports Records with same acessor fields
## Steps to reproduce
```hs
{-# LANGUAGE DuplicateRecordFields #-}
module A where
data R = MkR {ra :: Int, rb :: Bool}
data R' = MkR' {ra :: Int, rb :: Bool}
```
```hs
{-# LANGUAGE OverloadedRecordDot #-}
{-# OPTIONS_GHC -Wall #-}
module B where
import A (R (ra), rb) -- this line emits the warnings for `rb`
x :: R -> Bool
x a = a.rb
y :: R -> Int
y a = a.ra
```
## Expected behavior
No unused import warning
## Environment
* GHC version used: ghc 9.6.2
Optional:
* Operating System: NixOS 23.11
* System Architecture: x86_64-linuxsheafsam.derbyshire@gmail.comsheafsam.derbyshire@gmail.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/23992`$` converts ambiguous record update error to a warning2023-09-26T14:44:03ZEmeka Nkurumeh`$` converts ambiguous record update error to a warning## Summary
Inserting `$` between a function call and a record update can change ambiguous record update errors, into warnings. This behavior is specific to `$` since using `Data.Function.&` or aliasing `$` still produce error. As far as...## Summary
Inserting `$` between a function call and a record update can change ambiguous record update errors, into warnings. This behavior is specific to `$` since using `Data.Function.&` or aliasing `$` still produce error. As far as I can tell this seems to be a regression since before GHC 9.2.5, only type applications were able to change this error to a warning.
## Steps to reproduce
```haskell
{-# LANGUAGE DuplicateRecordFields #-}
data Foo1 = Foo1
{ foo :: Int
, bar :: Int
}
data Foo2 = Foo2
{ foo :: Int
, baz :: Int
}
setFoo :: Int -> Foo1 -> Foo1
setFoo x f = id f {foo = x}
```
GHC gives the following error:
```
Example.hs:14:17: error: [GHC-99339]
• Record update is ambiguous, and requires a type signature
• In the first argument of ‘id’, namely ‘f {foo = x}’
In the expression: id f {foo = x}
In an equation for ‘setFoo’: setFoo x f = id f {foo = x}
|
14 | setFoo x f = id f {foo = x}
|
```
If we insert a `$` into `setFoo` as so: `setFoo x f = id $ f {foo = x}`, we get a warning instead:
```
Example.hs:14:22: warning: [GHC-02256] [-Wambiguous-fields]
The record update f {foo = x} with type Foo1 is ambiguous.
This will not be supported by -XDuplicateRecordFields in future releases of GHC.
|
14 | setFoo x f = id $ f {foo = x}
|
```
## Expected behavior
Return the same error as if there were no `$`.
## Environment
* GHC version used: 9.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/23963Cannot disambiguate duplicate pattern synonym record fields in exports2023-10-06T13:18:39ZAdam GundryCannot disambiguate duplicate pattern synonym record fields in exportsConsider the following module:
```hs
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE PatternSynonyms #-}
module RecPatSyn (B(B, x)) where
data A = MkA {x_ :: Int}
data B = MkB {x_ :: Int}
pattern A :: Int...Consider the following module:
```hs
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE PatternSynonyms #-}
module RecPatSyn (B(B, x)) where
data A = MkA {x_ :: Int}
data B = MkB {x_ :: Int}
pattern A :: Int -> A
pattern A{x} <- MkA x
pattern B :: Int -> B
pattern B{x} <- MkB x
```
There is no way to express the fact that in the export list we mean the `x` originating from pattern synonym `B`. Hence this is rejected with an ambiguous occurrence error:
```
RecPatSyn.hs:5:19: error: [GHC-66025]
• Pattern synonyms can only be bundled with matching type constructors
Couldn't match expected type of ‘B’ with actual type of ‘A’
• In the pattern synonym record selector: x
In the export: B(B, x)
|
5 | module RecPatSyn (B(B, x)) where
| ^^^^^^^
RecPatSyn.hs:5:19: error: [GHC-87543]
• Ambiguous occurrence ‘x’.
It could refer to
either the field ‘x’ of pattern synonym ‘A’,
defined at RecPatSyn.hs:12:11,
or the field ‘x’ of pattern synonym ‘B’,
defined at RecPatSyn.hs:15:11.
• In the export: B(B, x)
|
5 | module RecPatSyn (B(B, x)) where
| ^^^^^^^
```
The "Pattern synonyms can only be bundled with matching type constructors" bit of the error seems to be bogus. Presumably the ambiguous identifier is "resolved" to the first option to allow type-checking to continue. But it leads to the awkward situation where the renamer considers it ambiguous which `x` is meant, yet the type-checker apparently "knows" that `x` cannot come from `A`.
It's not obvious to me how we could do better here, but it's an awkward corner of the `PatternSynonyms`/`DuplicateRecordFields` interaction that I wanted to record.
This was originally reported at https://discourse.haskell.org/t/how-to-export-record-pattern-synonym-duplicate-field-names-in-the-same-module/7594.https://gitlab.haskell.org/ghc/ghc/-/issues/23040`OverloadedRecordDot` and `COLUMN`-pragmas don't play nice together2023-02-28T15:27:27ZSimon Hengelsol@typeful.net`OverloadedRecordDot` and `COLUMN`-pragmas don't play nice together## Summary
`foo.foo` is accepted while `foo{-# COLUMN 23 #-}.foo` results in a parse error.
This is surprising from a users perspective and can break `OverloadedRecordDot` with source-to-source transformations / pre-processors (as it d...## Summary
`foo.foo` is accepted while `foo{-# COLUMN 23 #-}.foo` results in a parse error.
This is surprising from a users perspective and can break `OverloadedRecordDot` with source-to-source transformations / pre-processors (as it does for me).
## Steps to reproduce
```
{-# LANGUAGE NoFieldSelectors #-}
{-# LANGUAGE OverloadedRecordDot #-}
data Foo = Foo { foo :: String }
foo :: Foo
foo = Foo "foo"
main :: IO ()
main = do
putStrLn foo.foo -- works
putStrLn foo{-# COLUMN 23 #-}.foo -- parse error
```
## Expected behavior
Both `foo.foo` and `foo{-# COLUMN 23 #-}.foo` should be accepted.
## Investigation
`foo.foo` is tokenized to:
[ITvarid "foo", ITproj False, ITvarid "bar"]
However, `foo{-# COLUMN 23 #-}.foo` is tokenized to:
[ITvarid "foo", ITproj True, ITvarid "bar"]
So from what I understand, even though this manifests as a parse error, the bug is actually in the lexer.
## Environment
* GHC version used: 9.6.0.20230111
Optional:
* Operating System: Linux
* System Architecture: x86_64https://gitlab.haskell.org/ghc/ghc/-/issues/23032Disambiguating record updates in the renamer using as-patterns2023-06-05T12:06:39Zsheafsam.derbyshire@gmail.comDisambiguating record updates in the renamer using as-patternsI think the following could reasonably be expected to work:
```haskell
{-# LANGUAGE DuplicateRecordFields #-}
module M where
data A a = MkA { fld :: a }
data B b = MkB { fld :: b }
foo x r@(MkA{}) = r { fld = x }
```
When renaming the...I think the following could reasonably be expected to work:
```haskell
{-# LANGUAGE DuplicateRecordFields #-}
module M where
data A a = MkA { fld :: a }
data B b = MkB { fld :: b }
foo x r@(MkA{}) = r { fld = x }
```
When renaming the record update on the RHS of `foo`, the renamer would see `r`, and look up in some environment to see it is associated with the pattern `MkA{}` which disambiguates which record field `fld` refers to.
Currently `rnPat` doesn't create any kind of environment to keep track of the connection in an as-pattern:
```haskell
rnPatAndThen mk (AsPat _ rdr at pat)
= do { new_name <- newPatLName mk rdr
; pat' <- rnLPatAndThen mk pat
; return (AsPat noExtField new_name at pat') }
```
whereas the typechecker does:
```haskell
tc_pat pat_ty penv ps_pat thing_inside = case ps_pat of
...
AsPat x (L nm_loc name) at pat -> do
{ ...
; (wrap, bndr_id) <- setSrcSpanA nm_loc (tcPatBndr penv name pat_ty)
; (pat', res) <- tcExtendIdEnv1 name bndr_id $
tc_lpat (pat_ty `scaledSet`(mkCheckExpType $ idType bndr_id))
penv pat thing_inside
; ... }
```
I think this would be a rather satisfying way to disambiguate record updates, although one shortcoming is that it does not handle sum types very well, as one has to have a separate case for each constructor. We would want something like or-patterns:
```haskell
data C c = MkC1 { fld1, fld2, fld3 :: c } | MkC2 { fld1, fld2 :: c }
data D d = MkD1 { fld1, fld2 :: d }
-- OK, but requires listing all the constructors
bar1 c1 c2 r@(MkC1{} or MkC2{}) = r { fld1 = c1, fld2 = c2 }
-- Even better, just mention a single constructor!
bar2 c1 c2 r@(MkC1{} or _) = r { fld1 = c1, fld2 = c2 }
```https://gitlab.haskell.org/ghc/ghc/-/issues/22746How to disambiguate data family instances with duplicate record fields?2023-06-05T12:06:38ZPhil de JouxHow to disambiguate data family instances with duplicate record fields?## Summary
I have been upgrading from `ghc-8.10.7` to `ghc-9.2.5` and dealing with the `-Wambiguous-fields` warning as it is deprecating:
> This will not be supported by -XDuplicateRecordFields in future releases of GHC.
`-XOverloaded...## Summary
I have been upgrading from `ghc-8.10.7` to `ghc-9.2.5` and dealing with the `-Wambiguous-fields` warning as it is deprecating:
> This will not be supported by -XDuplicateRecordFields in future releases of GHC.
`-XOverloadedRecordDot` is very nice for field access. For record updates I've been qualifying field names to avoid the ambiguity.
I found a data family with multiple instances in the same module, each a record with `-XDuplicateRecordFields`, and could not find a way to import from this module qualified in order to disambiguate a record update.
## Steps to reproduce
See the repo https://github.com/typechecker/data-family-record-dot for these code snippets:
```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DuplicateRecordFields #-}
module DataFamily where
import Data.Kind
data Choice = A | B
data family Fam :: Choice -> Type
newtype instance Fam A = FamA{ field :: Int }
newtype instance Fam B = FamB{ field :: Bool }
```
```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE RecordWildCards #-}
module RecordUpdate where
import DataFamily (Choice(..))
import qualified DataFamily as WhoIsB (Fam(FamB), Fam(field))
toggleBool :: WhoIsB.Fam B -> WhoIsB.Fam B
toggleBool b@WhoIsB.FamB{..} =
b{ WhoIsB.field = not field}
```
```
$ cabal repl
Resolving dependencies...
Build profile: -w ghc-9.4.4 -O1
In order, the following will be built (use -v for more details):
- data-family-record-dot-0.1.0.0 (lib) (first run)
Configuring library for data-family-record-dot-0.1.0.0..
Preprocessing library for data-family-record-dot-0.1.0.0..
GHCi, version 9.4.4: https://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling DataFamily ( src/DataFamily.hs, interpreted )
[2 of 2] Compiling RecordUpdate ( src/RecordUpdate.hs, interpreted )
src/RecordUpdate.hs:7:1: warning: [-Wunused-imports]
The qualified import of ‘Fam(field)’
from module ‘DataFamily’ is redundant
|
7 | import qualified DataFamily as WhoIsB (Fam(FamB), Fam(field))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/RecordUpdate.hs:11:8: warning: [-Wambiguous-fields]
The record update b {WhoIsB.field = not
field} with type DataFamily.R:FamB is ambiguous.
This will not be supported by -XDuplicateRecordFields in future releases of GHC.
|
11 | b{ WhoIsB.field = not field}
| ^^^^^^^^^^^^^^^^^^^^^^^^
Ok, two modules loaded.
```
Note that if I followed the advice of the first warning and remove the qualified import of `Fam(field)` then I get an error.
```diff
- import qualified DataFamily as WhoIsB (Fam(FamB), Fam(field))
+ import qualified DataFamily as WhoIsB (Fam(FamB))
```
```
src/RecordUpdate.hs:11:8: error:
Not in scope: ‘WhoIsB.field’
Suggested fix:
Perhaps you want to add ‘field’ to the import list in the import of
‘DataFamily’ (src/RecordUpdate.hs:7:1-49).
|
11 | b{ WhoIsB.field = not field}
|
```
## Expected behavior
I'd expect to be able to use a qualified import to disambiguate. Is there a way? A workaround is to move one of the data family instances to another module, side-stepping the duplicate record field altogether, but that has import consequences for other consumers of the module (now two imports when there was one required to import all instances).
## Environment
ghc-9.4.4 and ghc-9.2.5 are the same here.https://gitlab.haskell.org/ghc/ghc/-/issues/22267OverloadedRecordDot is broken when records have a constraint2023-06-07T10:31:18ZGautier DI FOLCOOverloadedRecordDot is broken when records have a constraint## Summary
Whenever I try to reference a function with a constraint with OverloadedRecordDot syntax, I have an error.
## Steps to reproduce
While this code compiles:
```
{-# LANGUAGE OverloadedRecordDot #-}
module B where
data R = R...## Summary
Whenever I try to reference a function with a constraint with OverloadedRecordDot syntax, I have an error.
## Steps to reproduce
While this code compiles:
```
{-# LANGUAGE OverloadedRecordDot #-}
module B where
data R = R {myFunc :: String -> Int}
myUsage :: R -> Int
myUsage r = r.myFunc "42"
```
Adding a constraint:
```
{-# LANGUAGE OverloadedRecordDot #-}
module B where
import GHC.Stack
data R = R {myFunc :: HasCallStack => String -> Int}
myUsage :: R -> Int
myUsage r = r.myFunc "42"
```
gives me an error:
```
B.hs:9:13: error:
• No instance for (GHC.Records.HasField "myFunc" R (String -> Int))
arising from selecting the field ‘myFunc’
(maybe you haven't applied a function to enough arguments?)
• In the expression: r.myFunc
In the expression: r.myFunc "42"
In an equation for ‘myUsage’: myUsage r = r.myFunc "42"
|
9 | myUsage r = r.myFunc "42"
```
it also fails with a more classic one:
```
{-# LANGUAGE OverloadedRecordDot #-}
module B where
data R = R {myFunc :: forall a. Show a => a -> Int}
myUsage :: R -> Int
myUsage r = r.myFunc "42"
```
which gives
```
B.hs:7:13: error:
• No instance for (GHC.Records.HasField "myFunc" R (String -> Int))
arising from selecting the field ‘myFunc’
(maybe you haven't applied a function to enough arguments?)
• In the expression: r.myFunc
In the expression: r.myFunc "42"
In an equation for ‘myUsage’: myUsage r = r.myFunc "42"
|
7 | myUsage r = r.myFunc "42"
```
## Expected behavior
I expects the type-check works as there's no constraint (while propagating it).
## Environment
* GHC version used: 9.4.2 / 9.2.2
Optional:
* Operating System: NixOS unstable
* System Architecture: x86_64Gautier DI FOLCOGautier DI FOLCO