GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2023-06-16T08:33:20Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/9522SPECIALISE pragmas for derived instances2023-06-16T08:33:20ZSimon Peyton JonesSPECIALISE pragmas for derived instancesIn package `ghc-prim`, in `GHC.Classes` we have
```
instance (Eq a) => Eq [a] where
{-# SPECIALISE instance Eq [[Char]] #-}
{-# SPECIALISE instance Eq [Char] #-}
{-# SPECIALISE instance Eq [Int] #-}
[] == [] = Tr...In package `ghc-prim`, in `GHC.Classes` we have
```
instance (Eq a) => Eq [a] where
{-# SPECIALISE instance Eq [[Char]] #-}
{-# SPECIALISE instance Eq [Char] #-}
{-# SPECIALISE instance Eq [Int] #-}
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_xs == _ys = False
```
The `SPECIALISE instance` pragmas instantiate the code for these commonly-used types.
But for tuples we use `deriving`:
```
deriving instance (Eq a, Eq b) => Eq (a, b)
```
and many more similar. There is no way to add a `SPECIALISE instance` pragma for a derived instance. This is bad, because they are heavily used.
You can see the lossage from messages lie
```
WARNING: file compiler/specialise/Specialise.lhs, line 673
specImport discarding:
GHC.Classes.$w$c== :: forall a b. (Eq a, Eq b) => a -> b -> a -> b -> Bool
@ Module.Module @ Module.Module Module.$fEqModule Module.$fEqModule
```
which says that we will end up calling `$w$c==` for pairs of modules, passing dictionaries to compare the modules for equality. These messages show up when compiling the libraries if you build your stage1 compiler with `-DDEBUG`.
It should probably be possible to have a top-level
```
{-# SPECIALISE instance Eq (Int, Bool) #-}
```
even in another module (as we can now do for functions. To do this right, we'd need to make the code for derived methods `INLINEALBE`.https://gitlab.haskell.org/ghc/ghc/-/issues/9450GHC instantiates Data instances before checking hs-boot files2019-07-07T18:40:21ZAlan ZimmermanGHC instantiates Data instances before checking hs-boot filesWhen compiling a file with deriving instances in it and making use of boot files, it appears that the derivation is attempted before the boot files are checked for consistency.
This can lead to GHC panics, as when compiling GHC after th...When compiling a file with deriving instances in it and making use of boot files, it appears that the derivation is attempted before the boot files are checked for consistency.
This can lead to GHC panics, as when compiling GHC after this commit https://github.com/alanz/ghc/commit/c73182ca7345f0debba47d0b17a907bcac27c41f
In the attached files, if you try to load HsLit.lhs into ghci it will complain about the missing Data instance, not about the boot file inconsistency. If you remove the Data from the deriving clause of HsOverLit, it complains about the boot file inconsistency.
I have not managed to reproduce the original panic in this stripped down environment, but if it is needed to more fully understand the problem I can try again to do that.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC instantiates Data instances before checking hs-boot files","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":["boot,deriving"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"When compiling a file with deriving instances in it and making use of boot files, it appears that the derivation is attempted before the boot files are checked for consistency. \r\n\r\nThis can lead to GHC panics, as when compiling GHC after this commit https://github.com/alanz/ghc/commit/c73182ca7345f0debba47d0b17a907bcac27c41f\r\n\r\nIn the attached files, if you try to load HsLit.lhs into ghci it will complain about the missing Data instance, not about the boot file inconsistency. If you remove the Data from the deriving clause of HsOverLit, it complains about the boot file inconsistency.\r\n\r\nI have not managed to reproduce the original panic in this stripped down environment, but if it is needed to more fully understand the problem I can try again to do that.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/20815Make coerce-derived dictionaries coercible2023-12-15T08:14:25ZIcelandjackMake coerce-derived dictionaries coercibleTake the [`Alt`](https://hackage.haskell.org/package/semigroupoids-5.3.6/docs/Data-Functor-Alt.html) type class as an example, which is `Alternative` without the `empty` method:
```haskell
{-# Language ConstrainedClassMethods #-}
{-# La...Take the [`Alt`](https://hackage.haskell.org/package/semigroupoids-5.3.6/docs/Data-Functor-Alt.html) type class as an example, which is `Alternative` without the `empty` method:
```haskell
{-# Language ConstrainedClassMethods #-}
{-# Language DerivingVia #-}
import Control.Applicative
class Functor f => Alt f where
(<!>) :: f a -> f a -> f a
some :: Applicative f => f a -> f [a]
some v = some_v
where many_v = some_v <!> pure []
some_v = (:) <$> v <*> many_v
many :: Applicative f => f a -> f [a]
many v = many_v
where many_v = some_v <!> pure []
some_v = (:) <$> v <*> many_v
```
The applicative constraints on the methods means we cannot derive `Alt`.
If we try to derive it (say via `[]`) GHC fails to coerce between `Applicative []` and `Applicative List`.
```haskell
instance Alt [] where
(<!>) = (<>)
newtype List a = List [a]
-- • Couldn't match type ‘[]’ with ‘List’
-- arising from the coercion of the method ‘many’
-- from type ‘forall a. Applicative [] => [a] -> [[a]]’
-- to type ‘forall a. Applicative List => List a -> List [a]’
-- • When deriving the instance for (Alt List)
--
-- .. same for ‘some’
deriving (Functor, Applicative, Alt)
via []
```
GHC can make use of the provenence of the `Applicative` instance: we know that that `Applicative List` was derived via `Applicative []` using `coerce`-based deriving (either `newtype`, `via`) and so the dictionaries can be considered `Coercible` (?). If not I'm curious if this fails.¹
This is not the first time I want this (I forgot in what context though), let me know if it's sensible/useful.
----
¹ Instead of coercing method-by-method could `coerce`-based deriving coerce the whole dictionary?https://gitlab.haskell.org/ghc/ghc/-/issues/20099Inflexible DerivingVia2021-09-28T19:24:24ZJaro ReindersInflexible DerivingVia## Summary
I recently wanted to derive instances like `Functor` and `Applicative` for a datatype that has an `Arrow` instance. I thought this would be possible by deriving via the `ArrowMonad` type. Unfortunately this doesn't work.
## ...## Summary
I recently wanted to derive instances like `Functor` and `Applicative` for a datatype that has an `Arrow` instance. I thought this would be possible by deriving via the `ArrowMonad` type. Unfortunately this doesn't work.
## Steps to reproduce
Here is a minimal reproducer:
```haskell
{-# LANGUAGE DerivingVia #-}
import Control.Arrow
import Control.Category
data Test a b = Test a b
deriving Functor via ArrowMonad Test
-- details of these instances don't matter
instance Category Test
instance Arrow Test
```
This gives two related errors:
```
Sad.hs:6:35: error:
• Couldn't match representation of type ‘a’ with that of ‘()’
arising from the coercion of the method ‘<$’
from type ‘forall a b. a -> ArrowMonad Test b -> ArrowMonad Test a’
to type ‘forall a1 b. a1 -> Test a b -> Test a a1’
‘a’ is a rigid type variable bound by
the deriving clause for ‘Functor (Test a)’
at Sad.hs:6:35-41
• When deriving the instance for (Functor (Test a))
|
6 | data Test a b = Test a b deriving Functor via ArrowMonad Test
| ^^^^^^^
Sad.hs:6:35: error:
• Couldn't match representation of type ‘a’ with that of ‘()’
arising from the coercion of the method ‘fmap’
from type ‘forall a b.
(a -> b) -> ArrowMonad Test a -> ArrowMonad Test b’
to type ‘forall a1 b. (a1 -> b) -> Test a a1 -> Test a b’
‘a’ is a rigid type variable bound by
the deriving clause for ‘Functor (Test a)’
at Sad.hs:6:35-41
• When deriving the instance for (Functor (Test a))
|
6 | data Test a b = Test a b deriving Functor via ArrowMonad Test
| ^^^^^^^
```
## Expected behavior
It does kind of make sense, but I hoped the deriving mechanism would generate instances like this:
```haskell
instance Functor (Test ()) where
fmap :: forall a b. (a -> b) -> Test () a -> Test () b
fmap = coerce (fmap @(ArrowMonad Test) @a @b)
```
The `Test ()` could be inferred from the definition of `ArrowMonad`, namely:
```haskell
newtype ArrowMonad a b = ArrowMonad (a () b)
```
So `ArrowMonad Test a` has the same representation as `Test () a`.
I guess I don't really know if this is a bug or a feature request because this instance does require `FlexibleInstances` which might complicate things.
## Workaround
A workaround is to use standalone deriving, but that can get verbose, this is an example from a parser arrow and monad that I'm working on:
```haskell
newtype Parser a b = Parser { unParser :: (a, String) -> Steps (b, String) }
deriving (Category, Arrow, ArrowZero, ArrowPlus, ArrowChoice, ArrowApply)
via StateArrow String (Kleisli Steps)
deriving via ArrowMonad Parser instance Functor (Parser ())
deriving via ArrowMonad Parser instance Applicative (Parser ())
deriving via ArrowMonad Parser instance Alternative (Parser ())
deriving via ArrowMonad Parser instance Monad (Parser ())
deriving via ArrowMonad Parser instance MonadPlus (Parser ())
```
Another alternative is to change `ArrowMonad` to expose another type parameter:
```haskell
newtype ArrowMonad' a b c = ArrowMonad' (a b c)
```
(only the `Monad` instance needs a small change)
Then I could write:
```haskell
newtype Parser a b = Parser { unParser :: (a, String) -> Steps (b, String) }
deriving (Category, Arrow, ArrowZero, ArrowPlus, ArrowChoice, ArrowApply)
via StateArrow String (Kleisli Steps)
deriving (Functor, Applicative, Alternative, Monad, MonadPlus)
via ArrowMonad' Parser a
```
## Environment
* GHC version used: 8.10.4
Optional:
* Operating System: NixOS 21.05
* System Architecture: x86_64https://gitlab.haskell.org/ghc/ghc/-/issues/19906Should Generically (/ Generically1) derive newtype Generic (/ Generic1)?2021-05-30T15:01:27ZIcelandjackShould Generically (/ Generically1) derive newtype Generic (/ Generic1)?Regarding #17147 (!5726), this may be controversial and touch on the philosophy of Generic. "Generic" is universally derived using the *stock* deriving strategy. I propose deriving those instances for `Generically{,1}` using generalized ...Regarding #17147 (!5726), this may be controversial and touch on the philosophy of Generic. "Generic" is universally derived using the *stock* deriving strategy. I propose deriving those instances for `Generically{,1}` using generalized *newtype* deriving, by reusing the underlying `Generic{,1}` instances. This is in line with all other instances for `Generically{,1}` as they are defined using the generic representation of the underlying type.
```haskell
type Generically :: Type -> Type
newtype Generically a = Generically a
deriving
newtype Generic
type Generically1 :: (k -> Type) -> k -> Type
newtype Generically1 f a = Generically1 (f a)
deriving
newtype Generic1
```
That is to say be given the following instance
```haskell
instance Generic a => Generic (Generically a) where
type Rep (Generically a) = Rep a
from :: Generically a -> Rep a b
from (Generically a) = from a
to :: Rep a b -> Generically a
to = Generically . to
instance Generic1 f => Generic1 (Generically1 f) where
type Rep1 (Generically1 f) = Rep1 f
from1 :: Generically1 f a -> Rep1 f a
from1 (Generically1 as) = from1 as
to1 :: Rep1 f a -> Generically1 f a
to1 = Generically1 . to1
```
The other instances avoid newtype wrapping
```haskell
Generically a <> Generically b = Generically (to (from a <> from b :: Rep a ()))
mempty = Generically (to (mempty :: Rep a ()))
fmap f (Generically1 as) = Generically1 (to1 (fmap f (from1 as)))
a <$ Generically1 as = Generically1 (to1 (a <$ from1 as))
pure a = Generically1 (to1 (pure a))
Generically1 fs <*> Generically1 as = Generically1 (to1 (from1 fs <*> from1 as))
liftA2 (·) (Generically1 as) (Generically1 bs) = Generically1 (to1 (liftA2 (·) (from1 as) (from1 bs)))
empty = Generically1 (to1 empty)
Generically1 as1 <|> Generically1 as2 = Generically1 (to1 (from1 as1 <|> from1 as2))
```
--->
```haskell
a <> b = to (from a <> from b :: Rep a ())
mempty = to (mempty :: Rep a ())
fmap f = to1 . fmap f . from1
a <$ as = to1 (a <$ from1 as)
pure = to1 . pure
fs <*> as = to1 (from1 fs <*> from1 as)
liftA2 (·) as bs = to1 (liftA2 (·) (from1 as) (from1 bs))
empty = to1 empty
as1 <|> as2 = to1 (from1 as1 <|> from1 as2)
```https://gitlab.haskell.org/ghc/ghc/-/issues/19707[Discussion] Integrating DataTypeable, Functor, Foldable, Traversable, Generi...2023-06-10T10:51:12ZHécate Moonlight[Discussion] Integrating DataTypeable, Functor, Foldable, Traversable, Generic and Lift in the `stock` deriving strategyI wish to start a discussion around the possibility of integrating the numerous classes we offer in `base` in the `stock` deriving strategy by the removing the need to use language extensions to expose them to end-user.
This ticket is n...I wish to start a discussion around the possibility of integrating the numerous classes we offer in `base` in the `stock` deriving strategy by the removing the need to use language extensions to expose them to end-user.
This ticket is not meant to bypass a proper GHC Proposal, but I'd like to get some feedback from the GHC dev team and adjacent folks before starting a proposal process.
I personally think we may have reached the maturity where it would make sense to greatly simplify this aspect of the compiler, but I am not omniscient and clearly could use different perspectives. :)
---
Note: Matt Parsons has also raised this question in his article [Haskell Proposal: Simplify Deriving](https://www.parsonsmatt.org/2020/11/10/simplifying_deriving.html).https://gitlab.haskell.org/ghc/ghc/-/issues/5041Incorrect Read deriving for MagicHash constructors2021-09-29T09:32:20ZdolioIncorrect Read deriving for MagicHash constructorsGreetings,
A fellow in \#haskell on freenode just discovered the following bug:
```
{-# LANGUAGE MagicHash #-}
data Note = A# deriving (Show, Read)
```
show works fine, but read doesn't:
```
*Main> show A#
"A#"
*Main> read (show A#)...Greetings,
A fellow in \#haskell on freenode just discovered the following bug:
```
{-# LANGUAGE MagicHash #-}
data Note = A# deriving (Show, Read)
```
show works fine, but read doesn't:
```
*Main> show A#
"A#"
*Main> read (show A#)
*** Exception: Prelude.read: no parse
```
Probably not a surprising omission, and hopefully not difficult to fix.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.0.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Incorrect Read deriving for MagicHash constructors","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.0.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Greetings,\r\n\r\nA fellow in #haskell on freenode just discovered the following bug:\r\n\r\n{{{\r\n{-# LANGUAGE MagicHash #-}\r\n\r\ndata Note = A# deriving (Show, Read)\r\n}}}\r\n\r\nshow works fine, but read doesn't:\r\n\r\n{{{\r\n*Main> show A#\r\n\"A#\"\r\n*Main> read (show A#)\r\n*** Exception: Prelude.read: no parse\r\n}}}\r\n\r\nProbably not a surprising omission, and hopefully not difficult to fix.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/19713DeriveFunctor: Use `contramap' in contravariant position2021-04-19T03:44:35ZIcelandjackDeriveFunctor: Use `contramap' in contravariant positionThis rule for [*cofmap* in `GHC.Tc.Deriv.Functor`](https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Tc/Deriv/Functor.hs#L111) can not deal with a type variable in contravariant position
```
$(cofmap 'a 'b x) = x ...This rule for [*cofmap* in `GHC.Tc.Deriv.Functor`](https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Tc/Deriv/Functor.hs#L111) can not deal with a type variable in contravariant position
```
$(cofmap 'a 'b x) = x -- when b does not contain a
$(cofmap 'a 'a x) = error "type variable in contravariant position"
$(cofmap 'a '(b1,b2) x) = case x of (x1,x2) -> ($(cofmap 'a 'b1) x1, $(cofmap 'a 'b2) x2)
$(cofmap 'a '(T b1 a) x) = error "type variable in contravariant position" -- when a only occurs directly as the last argument of T
$(cofmap 'a '(T b1 b2) x) = fmap (\y. $(cofmap 'a 'b2 y)) x -- when a only occurs in the last parameter, b2
$(cofmap 'a '(tb -> tc) x) = \(y:tb[b/a]) -> $(cofmap 'a' 'tc' (x $(fmap 'a 'tb y)))
```
but now that we have `Data.Functor.Contravariant` in base why not generate an invocation to `contramap`?
```
$(cofmap 'a '(T b1 a) x) = contramap f x
```
As an example, this works becuase of the special case for functions
```
> :set -XDerivingStrategies -XDeriveFunctor
> newtype F a = MkF ((a -> Int) -> Int) deriving stock Functor
```
but if we use `Op Int a` (which is a newtype wrapping `a -> Int`) ghc does not know how to derive it.
```
> newtype F a = MkF (Op Int a -> Int) deriving stock Functor
<interactive>:10:52: error:
• Can't make a derived instance of
‘Functor F’ with the stock strategy:
Constructor ‘MkF’ must not use the type variable in a function argument
• In the newtype declaration for ‘F’
```
I claim it should work by inserting a `contramap` invocation there so both these definitions
```haskell
newtype F a = MkF (Op Int a -> Int) deriving stock Functor
newtype F a = MkF (Equivalence a -> Int) deriving stock Functor
```
would generate the following (basically)
```haskell
instance Functor F where
fmap :: (a -> a') -> (F a -> F a')
fmap f (MkF as) = MkF (fmap as (contramap f))
```https://gitlab.haskell.org/ghc/ghc/-/issues/19418Support overriding "No instance" errors using the default deriving strategy2021-03-02T01:20:51Zinfinity0Support overriding "No instance" errors using the default deriving strategy## Motivation
Consider this code:
```haskell
data FooState a b c d = FooState
{ partA :: a
, partB :: b
, partC :: c
, partD :: d
}
deriving (Show, Read)
withFoo :: FooState a b c d -> FooState a b c d
withFoo = undefined
...## Motivation
Consider this code:
```haskell
data FooState a b c d = FooState
{ partA :: a
, partB :: b
, partC :: c
, partD :: d
}
deriving (Show, Read)
withFoo :: FooState a b c d -> FooState a b c d
withFoo = undefined
```
Eugh, the API has 4 type params. This is confusing for users, especially when they combine it with other functions that take additional type params. In fact (a, b, c, d) are logically "our" (as the author of `FooState`) type params, so we can simplify it like this, by grouping them together:
```haskell
{-# LANGUAGE TypeFamilies #-}
class FooParams p where
type FooA p
type FooB p
type FooC p
type FooD p
data FooState' p = FooState'
{ partA :: FooA p
, partB :: FooB p
, partC :: FooC p
, partD :: FooD p
}
-- deriving (Show, Read) -- fails!
withFoo' :: FooParams p => FooState' p -> FooState' p
withFoo' = undefined
```
<details>
<summary>(Alternatively, using more advanced language features you can even avoid the typeclass context, although this prevents you defining class methods on FooA etc, click for details)
</summary>
```haskell
{-# LANGUAGE TypeFamilies, RankNTypes, PolyKinds, DataKinds, StandaloneKindSignatures #-}
data FooParams aT bT cT dT = FooParams
{ fooA :: aT
, fooB :: bT
, fooC :: cT
, fooD :: dT
}
type FooA :: forall a b c d. FooParams a b c d -> *
type family FooA p where FooA ('FooParams a b c d) = a
type FooB :: forall a b c d. FooParams a b c d -> *
type family FooB p where FooB ('FooParams a b c d) = b
type FooC :: forall a b c d. FooParams a b c d -> *
type family FooC p where FooC ('FooParams a b c d) = c
type FooD :: forall a b c d. FooParams a b c d -> *
type family FooD p where FooD ('FooParams a b c d) = d
data FooState' (p :: FooParams a b c d) = FooState'
{ partA :: FooA p
, partB :: FooB p
, partC :: FooC p
, partD :: FooD p
}
-- deriving (Show, Read) -- fails!
withFoo' :: FooState' p -> FooState' p
withFoo' = undefined
```
</details>
Either way, great, our API now only has 1 type param.
Unfortunately, now `deriving (Show, Read)` fails (in both examples):
~~~~
Test.hs:26:13: error:
• No instance for (Show (FooA p))
arising from the first field of ‘FooState'’ (type ‘FooA p’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Show (FooState' p))
|
26 | deriving (Show, Read)
| ^^^^
Test.hs:26:19: error:
• No instance for (Read (FooA p))
arising from the first field of ‘FooState'’ (type ‘FooA p’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Read (FooState' p))
|
26 | deriving (Show, Read)
| ^^^^
~~~~
We can currently work around this in 2 ways, neither of which is ideal:
<details>
<summary>standalone deriving, tedious manual context</summary>
```haskell
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-}
class FooParams p where
type FooA p
type FooB p
type FooC p
type FooD p
data FooState' p = FooState'
{ partA :: FooA p
, partB :: FooB p
, partC :: FooC p
, partD :: FooD p
}
-- manually supply the context, eugh
-- increases n*m with number of associated types, and the number of extra instances e.g. Eq, Ord
deriving instance (Show (FooA p), Show (FooB p), Show (FooC p), Show (FooD p)) => Show (FooState' p)
deriving instance (Read (FooA p), Read (FooB p), Read (FooC p), Read (FooD p)) => Read (FooState' p)
withFoo' :: FooParams p => FooState' p -> FooState' p
withFoo' = undefined
```
</details>
<details>
<summary>extra type synonym, slightly ugly API</summary>
```haskell
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class FooParams p where
type FooA p
type FooB p
type FooC p
type FooD p
-- data decl still has 4 type params
data FooState a b c d = FooState
{ partA :: a
, partB :: b
, partC :: c
, partD :: d
}
deriving (Show, Read)
-- apply the type family in a synonym, and expose this along with
-- the constructor of the original data type if necessary.
-- however, this gets ugly if the data structure is more complex
type FooState'' p = FooState (FooA p) (FooB p) (FooC p) (FooD p)
-- API methods can use the type synonym to reduce the number of params
withFoo'' :: FooParams p => FooState'' p -> FooState'' p
withFoo'' = undefined
```
</details>
## Proposal
I guess the error is a purposeful design choice to avoid surprising users - the same error occurs if e.g. using `IO p` instead of `FooA p`, and the same workarounds also work. Clearly, successfully and silently generating an instance with the context `(Show (IO p) .. ) =>`, would be surprising to users.
However for certain use-cases such as the one I just described, this "potentially-surprising" derived instance is in fact what we want, and is not surprising for these particular cases (e.g. think `Maybe p`). So it would be good if we could override the error and tell GHC to just use what it would have output. This could possibly be implemented as a new strategy with a name such as "stock_relaxed" or "stock_unchecked" or something.https://gitlab.haskell.org/ghc/ghc/-/issues/18874Deriving multiple classes in standalone (or document this limitation)2022-12-08T00:32:14ZJulien DebonDeriving multiple classes in standalone (or document this limitation)## Motivation
To the best of my knowledge (I could not find any information about it in the [GHC Standalone Deriving documentation](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#stand-alone-deriving-d...## Motivation
To the best of my knowledge (I could not find any information about it in the [GHC Standalone Deriving documentation](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#stand-alone-deriving-declarations)), it is not possible to derive multiple classes in a single standalone deriving declaration.
Repeating an identical deriving declaration only to change the derived instance seems like unnecessary boilerplate:
```haskell
deriving instance Eq (MyType 'Foo)
deriving instance Show (MyType 'Foo)
deriving instance Read (MyType 'Foo)
```
But this situation can actually become bug-prone when used together with `via` strategy, as it becomes easy to have discrepancies. Example using [deriving-aeson](https://hackage.haskell.org/package/deriving-aeson) library:
```haskell
deriving via
( CustomJSON
'[ OmitNothingFields,
UnwrapUnaryRecords,
TagSingleConstructors,
FieldLabelModifier (StripPrefix "user", CamelToSnake)
]
)
instance
ToJSON (MyType 'Foo)
deriving via
( CustomJSON
'[ OmitNothingFields, -- Oh, we forgot to add 'UnwrapUnaryRecords' here!
TagSingleConstructors,
FieldLabelModifier (StripPrefix "user", CamelToSnake)
]
)
instance
FromJSON (MyType 'Foo)
```
## Proposal
I propose GHC supports deriving several instances in a single standalone declaration.
I don't have a strong opinion on the syntax (nor have I put a lot of effort in thinking about it, I have to admit), though I give an example of what it could look like below:
```haskell
deriving instance (Eq, Show, Read) (MyType 'Foo)
deriving via
( CustomJSON
'[ OmitNothingFields,
UnwrapUnaryRecords,
TagSingleConstructors,
FieldLabelModifier (StripPrefix "user", CamelToSnake)
]
)
instance
(ToJSON, FromJSON) (MyType 'Foo)
```
Should this proposal get rejected, I think we should at least document this limitation.https://gitlab.haskell.org/ghc/ghc/-/issues/18219Relax inferred context simplification to allow "exotic" contexts for Generali...2020-05-24T02:05:34ZAndrew PritchardRelax inferred context simplification to allow "exotic" contexts for GeneralizedNewtypeDeriving and DerivingVia instances.## Motivation
Many `GND` / `DerivingVia` instances that seem totally sensible must in practice be turned into `StandaloneDeriving` because their contexts cannot be inferred. However, `inferConstraintsCoerceBased` is already producing a...## Motivation
Many `GND` / `DerivingVia` instances that seem totally sensible must in practice be turned into `StandaloneDeriving` because their contexts cannot be inferred. However, `inferConstraintsCoerceBased` is already producing a sensible context for them, and all that's failing is simplifying that context. I suspect it's possible to simplify them differently from contexts coming from other deriving mechanisms, and make these deriving clauses work.
## Proposal
The following module defines a class and attempts to GND an instance of it, but fails because the inferred constraint simplifies to `C [a]`, which doesn't match any instance head.
```
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Example (Thing) where
class C a where method :: a -> String
instance C [Bool] where method _ = ""
newtype Thing a = Thing [a] deriving newtype C
```
This happens because of the restriction described in the Note `[Exotic derived instance contexts]`. However, many uses of `DerivingVia` intuitively want to "just copy the context of the via instance". I'm having a hard time formalizing this intuition, since there can be odd situations like mutually recursive derived instances involving newtypes [1] or self-recursive newtypes [2]. But a first pass is that if the `via` type is imported from another module and does not use the newtype itself as a type parameter, the system of equations being simplified for the GND instance can't be recursive, and it should suffice to simplify the context in isolation.
I tried horribly hacking up a GHC build to skip all simplification for GND and DerivingVia instances just to make sure it's only the simplification that's breaking the instance, and it sort-of worked, in that it inferred a context that had unsimplified Coercible constraints but was otherwise reasonable:
```
b87b0c2c2947e1ccc983269180bfe604
$fCThing ::
(C [a],
([a] -> GHC.Base.String) ~R# (Thing a -> GHC.Base.String)) =>
C (Thing a)
DFunId
[]
```
These unsimplified Coercible constraints are a problem, though, since they break calling modules that don't import the relevant newtype constructors (and the stage2 GHC doesn't build). Of course this isn't meant to be a real implementation, just a way to prove to myself that `inferContextCoerceBased` was sufficient for these instances.
In general many of the new instances this enables would probably require `UndecidableInstances`, but I'm willing to enable that as necessary. Some more example modules affected by this:
A type family interfering with simplification:
```
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Test where
import Data.Proxy (Proxy(..))
import GHC.TypeNats (Nat, KnownNat, natVal)
data SwarmOfNats = SwarmOfNats Nat Nat Nat
type family FstSwarm (x :: SwarmOfNats) :: Nat where
FstSwarm ('SwarmOfNats x y z) = x
class C a where method :: a -> String
instance KnownNat n => C (Proxy n) where method _ = show (natVal @n Proxy)
-- Fails simplifying because the context contains a type family application.
newtype Thing swarm = Thing (Proxy (FstSwarm swarm)) deriving newtype C
-- deriving newtype instance KnownNat (FstSwarm swarm) => C (Thing swarm)
```
A `FlexibleContexts` constraint on a MPTC interfering with simplification:
```
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Test where
-- Disregard that this technique is blatantly overkill here...
data Rope str = Leaf str | Append (Rope str) (Rope str) deriving Foldable
class C str a where method :: a -> Rope str
newtype WrappedC a = WrappedC { unWrappedC :: a }
instance C String a => Show (WrappedC a) where
showsPrec _p x s = foldr (++) s (method (unWrappedC x))
instance C [Char] a => C [Char] (Thing a) where
method Thing1 = Leaf "Thing1"
method (Thing2 x) = Append (Leaf "Thing2 ") (method x)
-- Fails because the inferred context simplifies to `C [Char] a`.
data Thing a = Thing1 | Thing2 a deriving Show via WrappedC (Thing a)
-- deriving via WrappedC (Thing a) instance C [Char] a => Show (Thing a)
```
[1]: A GND instance that would give a recursive system:
```
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Test where
data Thing1 = Thing1 Thing2 Thing2 deriving Eq
newtype Thing2 = Thing2 Thing1 deriving newtype Eq
-- Eq Thing1 = Eq Thing2 u Eq Thing2
-- Eq Thing2 = Eq Thing1 u Coercible Thing2 Thing1
```
[2] A GND instance that would expand infinitely (but works because of the least-fixed-point simplification):
```
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Test where
data Proxy a = Proxy
class ShowType a where showType :: Proxy a -> String
data Thing1 a
instance ShowType a => ShowType (Thing1 a) where
showType _ = "Thing1 " ++ showType (Proxy :: Proxy a)
newtype Weird a = Weird (Thing1 (Weird [a])) deriving newtype ShowType
-- ShowType (Weird a) = ShowType (Thing1 (Weird [a]))
-- = ShowType (Weird [a])
-- = ShowType (Thing1 (Weird [[a]]))
-- = ShowType (Weird [[a]])
-- ...
```https://gitlab.haskell.org/ghc/ghc/-/issues/24323Non-standalone deriving clause does not pick up superclass quantified coercib...2024-01-16T15:13:54ZShea Levyshea@shealevy.comNon-standalone deriving clause does not pick up superclass quantified coercible constraint## Summary
I have a case where a standalone deriving via typechecks but the non-standalone equivalent does not due to unknown roles, despite the derived class constraining the roles appropriately:
```haskell
{-# LANGUAGE DerivingVia #-...## Summary
I have a case where a standalone deriving via typechecks but the non-standalone equivalent does not due to unknown roles, despite the derived class constraining the roles appropriately:
```haskell
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE QuantifiedConstraints #-}
module Test where
import Control.Exception
import Data.Coerce
import Control.Monad.Trans.Reader
class (Monad m, forall x y. Coercible x y => Coercible (m x) (m y)) => MonadWith m where
stateThreadingGeneralWith
:: GeneralAllocate m SomeException releaseReturn b a
-> (a -> m b)
-> m (b, releaseReturn)
{-
newtype FooT m a = FooT (ReaderT Int m a) deriving newtype (Functor, Applicative, Monad) deriving MonadWith via ReaderT Int m
Test.hs:46:99: error:
• Couldn't match representation of type: m (GeneralAllocated
(ReaderT Int m) SomeException releaseReturn b a)
with that of: m (GeneralAllocated
(FooT m) SomeException releaseReturn b a)
arising from the coercion of the method ‘stateThreadingGeneralWith’
from type ‘forall releaseReturn b a.
GeneralAllocate (ReaderT Int m) SomeException releaseReturn b a
-> (a -> ReaderT Int m b) -> ReaderT Int m (b, releaseReturn)’
to type ‘forall releaseReturn b a.
GeneralAllocate (FooT m) SomeException releaseReturn b a
-> (a -> FooT m b) -> FooT m (b, releaseReturn)’
NB: We cannot know what roles the parameters to ‘m’ have;
we must assume that the role is nominal
• When deriving the instance for (MonadWith (FooT m))
|
46 | newtype FooT m a = FooT (ReaderT Int m a) deriving newtype (Functor, Applicative, Monad) deriving MonadWith via ReaderT Int m
| ^^^^^^^^^
Same issue with:
newtype FooT m a = FooT (ReaderT Int m a) deriving newtype (Functor, Applicative, Monad, MonadWith)
-}
newtype FooT m a = FooT (ReaderT Int m a) deriving newtype (Functor, Applicative, Monad)
deriving via ReaderT Int m instance (MonadWith m) => MonadWith (FooT m)
newtype GeneralAllocate m e releaseReturn releaseArg a
= GeneralAllocate ((forall x. m x -> m x) -> m (GeneralAllocated m e releaseReturn releaseArg a))
data GeneralAllocated m e releaseReturn releaseArg a = GeneralAllocated
{ allocatedResource :: !a
, releaseAllocated :: !(Either e releaseArg -> m releaseReturn)
}
instance (MonadWith m) => MonadWith (ReaderT r m) where
stateThreadingGeneralWith
:: forall a b releaseReturn
. GeneralAllocate (ReaderT r m) SomeException releaseReturn b a
-> (a -> ReaderT r m b)
-> ReaderT r m (b, releaseReturn)
stateThreadingGeneralWith (GeneralAllocate allocA) go = ReaderT $ \r -> do
let
allocA' :: (forall x. m x -> m x) -> m (GeneralAllocated m SomeException releaseReturn b a)
allocA' restore = do
let
restore' :: forall x. ReaderT r m x -> ReaderT r m x
restore' mx = ReaderT $ restore . runReaderT mx
GeneralAllocated a releaseA <- runReaderT (allocA restore') r
let
releaseA' relTy = runReaderT (releaseA relTy) r
pure $ GeneralAllocated a releaseA'
stateThreadingGeneralWith (GeneralAllocate allocA') (flip runReaderT r . go)
```
## Expected behavior
Both of these should behave the same, and should both work. I think this should also work with `deriving newtype` instead of having to specify the `via` type.
## Environment
* GHC version used: 9.2.4, 9.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/19445(Derived) Ord instances generate terrible code2022-11-22T09:59:00ZSebastian Graf(Derived) Ord instances generate terrible codeConsider these attempts at coming up with more compact `compare` functions:
```hs
{-# OPTIONS_GHC -O2 -fforce-recomp #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
module Lib (foo, bar, b...Consider these attempts at coming up with more compact `compare` functions:
```hs
{-# OPTIONS_GHC -O2 -fforce-recomp #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
module Lib (foo, bar, baz) where
import GHC.Exts
import GHC.Classes
data U = U Int deriving Eq
instance Ord U where
-- so that this function isn't WW'd
compare ~(U a) ~(U b) = lazy $ compare a b
{-# NOINLINE compare #-}
data T
= T0 U
| T1 U
| T2 U
| T3 U
| T4 U
| T5 U
deriving (Eq, Ord)
foo :: T -> T -> Ordering
foo = compare @T
bar :: T -> T -> Ordering
bar !_ r | !_ <- dataToTag# r, id False = undefined
bar (T0 a1) (T0 a2) = compare a1 a2
bar (T1 a1) (T1 a2) = compare a1 a2
bar (T2 a1) (T2 a2) = compare a1 a2
bar (T3 a1) (T3 a2) = compare a1 a2
bar (T4 a1) (T4 a2) = compare a1 a2
bar (T5 a1) (T5 a2) = compare a1 a2
bar l r
| isTrue# (dataToTag# l <# dataToTag# r) = LT
| otherwise = GT
baz :: T -> T -> Ordering
baz l r = compareInt# (dataToTag# l) (dataToTag# r) <> go l r
where
go (T0 a1) (T0 a2) = compare a1 a2
go (T1 a1) (T1 a2) = compare a1 a2
go (T2 a1) (T2 a2) = compare a1 a2
go (T3 a1) (T3 a2) = compare a1 a2
go (T4 a1) (T4 a2) = compare a1 a2
go (T5 a1) (T5 a2) = compare a1 a2
```
`bar` speculates `dataToTag#` on the second argument, so that its result is shared among all case branches. `baz` goes a step further: It simply compares tags and only compares fields when the tags match.
Here's the generated Core for the `T3` case:
```
foo a b_aLh = case a of {
T3 a1_aLp ->
case dataToTag# @T b_aLh of b#_aLq { __DEFAULT ->
case <# b#_aLq 3# of {
__DEFAULT ->
case b_aLh of {
__DEFAULT -> GHC.Types.LT;
T3 b1_aLr -> Lib.foo_$ccompare a1_aLp b1_aLr
};
1# -> GHC.Types.GT
}
}
}
bar a b_aLh =
case dataToTag# @T b_aLh of ds1_dU3 { __DEFAULT ->
case a of {
T3 a1_aJb ->
case b_aLh of {
__DEFAULT ->
case <# 3# ds1_dU3 of {
__DEFAULT -> GHC.Types.GT;
1# -> GHC.Types.LT
};
T3 a2_aJc -> Lib.foo_$ccompare a1_aJb a2_aJc
};
}
}
baz l_aJj r_aJk =
case dataToTag# @T r_aJk of wild_X1 { __DEFAULT ->
case dataToTag# @T l_aJj of wild1_X2 { __DEFAULT ->
case <# wild1_X2 wild_X1 of {
1# -> GHC.Types.LT;
__DEFAULT ->
case ==# wild1_X2 wild_X1 of {
__DEFAULT -> GHC.Types.GT;
1# ->
case l_aJj of {
T3 a1_aJs ->
case r_aJk of {
__DEFAULT -> Lib.baz1; -- pattern match error thunk
T3 a2_aJt -> Lib.foo_$ccompare a1_aJs a2_aJt
};
}
}
}
```
That is I think about the Core I'd expect, with one exception: I'd hoped that GHC would detect that the pattern match error in `baz` is impossible, which it doesn't.
Although `baz` looks rather big, I expected most of it to lower to very simple instructions. Well, `nm --print-size --size-sort test.o` reveals:
```
0000000000001180 000000000000032f T Lib_bar_info
0000000000000b00 0000000000000373 T Lib_foo_info
00000000000014c8 000000000000038f T Lib_bazz_info
```
So `bar` is a bit smaller than `foo` (the stock derived function), while `baz` is larger. All of them are quite large: They range between 0x300 (768) and 0x400 (1024) bytes!
I had a cursory look at the Cmm, and I was lost almost instantly. That was due to #19444, I think.
It's surely possible to generate more compact code for derived `Ord` instances. It's so common, yet so much more inefficient to do the equivalent in C!https://gitlab.haskell.org/ghc/ghc/-/issues/17518Can't derive TYPE rep instances2022-09-19T16:19:11ZIcelandjackCan't derive TYPE rep instances## Summary
Deriving fails when we have `TYPE rep`, not `Type`
```haskell
{-# Language DerivingStrategies #-}
{-# Language GeneralizedNewtypeDeriving #-}
{-# Language KindSignatures #-}
{-# Language MagicHash ...## Summary
Deriving fails when we have `TYPE rep`, not `Type`
```haskell
{-# Language DerivingStrategies #-}
{-# Language GeneralizedNewtypeDeriving #-}
{-# Language KindSignatures #-}
{-# Language MagicHash #-}
{-# Language PolyKinds #-}
{-# Language UnliftedNewtypes #-}
import GHC.Exts (TYPE, RuntimeRep(IntRep), Int#, (+#))
import Data.Coerce
class Num# (a# :: TYPE rep) where
add# :: a# -> a# -> a#
instance Num# Int# where
add# = (+#)
-- • Cannot derive well-kinded instance of form ‘Num# (IdInt# ...)’
-- Class ‘Num#’ expects an argument of kind ‘*’
-- • In the newtype declaration for ‘IdInt#’
newtype IdInt# = IdInt# Int#
deriving
newtype Num#
```
deriving works for a levity-polymorphic `Id#`
```haskell
newtype Id# (a# :: TYPE rep) = Id# a#
deriving
newtype Num#
```
but sadly only for `@LiftedRep`
```
> :set -fprint-explicit-kinds
> :i Num#
..
instance Num# @'LiftedRep a# =>
Num# @'LiftedRep (Id# @'LiftedRep a#)
```
## Proposed improvements or changes
The first one should be derived at `TYPE IntRep`
```haskell
instance Num# (IdInt# :: TYPE IntRep) where
add# :: IdInt# -> IdInt# -> IdInt#
add# = coerce (add# @IntRep @Int#)
```
but the second one wouldn't work for all `rep`, how can we get it to work
```haskell
-- Cannot use function with levity-polymorphic arguments:
-- coerce :: (a# -> a# -> a#) -> Id# a# -> Id# a# -> Id# a#
-- Levity-polymorphic arguments:
-- Id# a# :: TYPE rep
-- Id# a# :: TYPE rep^[[0m^[[0m
instance Num# a# => Num# (Id# a# :: TYPE rep) where
add# :: Id# a# -> Id# a# -> Id# a#
add# = coerce (add# @rep @a#)
```
## Environment
* GHC version used: 8.10.0.20191123
https://gitlab.haskell.org/ghc/ghc/-/issues/17183-XDerivingVia (and deriving strategies) is under specified in the manual2023-06-09T10:09:43ZRichard Eisenbergrae@richarde.dev-XDerivingVia (and deriving strategies) is under specified in the manualI had forgotten the syntax for deriving-strategies. Specifically, I wanted to know whether I had to put the strategy *before* or *after* the list of classes. So I looked it up.... but the [manual](https://downloads.haskell.org/~ghc/lates...I had forgotten the syntax for deriving-strategies. Specifically, I wanted to know whether I had to put the strategy *before* or *after* the list of classes. So I looked it up.... but the [manual](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#deriving-strategies) doesn't say. The examples suggest that the strategy comes before, but then in the `-XDerivingVia` section, the strategy comes after. Are both allowed? Is `via` allowed prefix? It is a mystery.
And then I looked through the `-XDerivingVia` [documentation](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#deriving-via). That is explained entirely by example, with no standalone specification. Yet the specification really has been worked out -- it's in the paper. This text should be incorporated into the users' guide, along with a link to the paper (which I also did not see). Also needed are a description of how typing works -- or at least scoping. It's very non-trivial.https://gitlab.haskell.org/ghc/ghc/-/issues/19936Odd GND failure/success2021-06-08T14:22:57ZDavid FeuerOdd GND failure/successThere's currently a discussion about whether to change the definition of `MonadTrans` to use `QuantifiedConstraints`:
```haskell
class (forall m. Monad m => Monad (t m)) => MonadTrans t where
lift :: m a -> t m a
```
I wondered if th...There's currently a discussion about whether to change the definition of `MonadTrans` to use `QuantifiedConstraints`:
```haskell
class (forall m. Monad m => Monad (t m)) => MonadTrans t where
lift :: m a -> t m a
```
I wondered if this works with GND. As it turns out, the answer is yes:
```haskell
newtype B t (m :: Type -> Type) a => B (t m a)
deriving (Functor, Applicative, Monad)
-- StandaloneDeriving just to be sure the constraints is
-- what I expect.
deriving instance MonadTrans t => MonadTrans (B t)
```
compiles just fine. But a conceptually very similar idea does not:
```haskell
class MonadTrans t where
lift :: m a -> t m a
liftMonad :: Monad m => Proxy (t m) -> (Monad (t m) => r) -> r
```
This one produces an error,
```
Lift.hs:9:42: error:
• Occurs check: cannot construct the infinite type: t ~ B t
arising from the coercion of the method ‘liftMonad’
from type ‘forall (m :: * -> *) r.
Monad m =>
Proxy (t m) -> (Monad (t m) => r) -> r’
to type ‘forall (m :: * -> *) r.
Monad m =>
Proxy (B t m) -> (Monad (B t m) => r) -> r’
• When deriving the instance for (MonadTrans (B t))
```
Why does one work and not the other? Is there a good reason for that, or should they both succeed or both fail?https://gitlab.haskell.org/ghc/ghc/-/issues/23462"Instance head is not headed by a class" error message is less clear than mes...2023-06-17T07:12:31ZGregory Gerasev"Instance head is not headed by a class" error message is less clear than message for type family use corner case## Summary
Consider this code:
```
data MyType
type MyConstraint x = Eq x
deriving stock instance MyConstraint MyType
```
GHC produces clear explanation in error message:
```
Illegal instance for a type synonym
A class instance must ...## Summary
Consider this code:
```
data MyType
type MyConstraint x = Eq x
deriving stock instance MyConstraint MyType
```
GHC produces clear explanation in error message:
```
Illegal instance for a type synonym
A class instance must be for a class
```
But when I run this:
> deriving stock instance forall (c :: Type -> Constraint). c MyType
Or even more simple example:
> deriving stock instance forall (c :: Constraint). c
GHC produces much less clear comment:
> Instance head is not headed by a class: c MyType
It seems to me that the problem is not related to "headed by a class".
Trick with `(c' ~ c MyType, ..` does not work in that case.
Why would one need this code?
I tried to derive `Some` wrapper constraints from wrapped class.
In my case:
```
import Data.Kind
data EntityKind x -- Ommited GADT
class Entity x -- Ommited class
data Some (container :: Type -> Type)
= forall entity.
Entity entity =>
MkSome (EntityKind entity) (container entity)
deriving stock instance
forall (x :: Constraint) (c :: Type -> Constraint) (container :: Type -> Type) .
(forall entity. (Entity entity, c entity) => c (container entity), c (Some container) ~ x) => x
```
## Proposed improvements or changes
I do not know. If `forall c.` does not make sense, than not clear error is probably not important.
But my deriving case seems possible in principle. Is not it?
Maybe I am missing some previous issues, but they did not take such `QuantifiedConstraints` usage into account.
## Environment
* GHC version used: 9.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/18213GND generates code that instantiates coerce too much2020-10-31T21:03:41ZRyan ScottGND generates code that instantiates coerce too muchConsider this code from https://gitlab.haskell.org/ghc/ghc/issues/18148#note_270603:
```hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUA...Consider this code from https://gitlab.haskell.org/ghc/ghc/issues/18148#note_270603:
```hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
module Bug where
class Foo a where
bar :: forall (x :: a). ()
bar = ()
instance Foo Int
newtype Quux a = Quux a
-- deriving newtype instance _ => Foo (Quux Int)
deriving newtype instance Foo (Quux Int)
```
This typechecks in GHC 8.10.1. However, if you comment out the original `deriving newtype instance Foo (Quux Int)` line and uncomment the very similar line above it, it no longer typechecks:
```
Bug.hs:19:1: error:
• Couldn't match type ‘Int’ with ‘Quux Int’
arising from the coercion of the method ‘bar’
from type ‘forall (x :: Int). ()’
to type ‘forall (x :: Quux Int). ()’
• When deriving the instance for (Foo (Quux Int))
|
19 | deriving newtype instance _ => Foo (Quux Int)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
This is a strange inconsistency, given how similar these standalone `deriving` declarations are. Why does the original succeed but the line above it fail?
As it turns out, both of these really ought to fail, but the original only succeeds due to an unfortunate fluke in the way `GeneralizedNewtypeDeriving` works. Here is the code that the original declaration generates (with `-ddump-deriv`):
```
==================== Derived instances ====================
Derived class instances:
instance Bug.Foo (Bug.Quux GHC.Types.Int) where
Bug.bar
= GHC.Prim.coerce @() @() (Bug.bar @GHC.Types.Int) ::
forall (x_aKF :: Bug.Quux GHC.Types.Int). ()
```
Notice that we are instantiating `coerce` with `@() @()`. But this is blatantly wrong—it really ought to be `coerce @(forall (x :: Int). ()) @(forall (x :: Quux Int). ())`, which the typechecker would reject (as it should). But GND generates `coerce @() @()` instead, and as a result, the use of `bar` on the RHS gets instantiated with `@Any`, which is not what was intended at all.
In contrast, the `deriving newtype instance _ => Foo (Quux Int)` line infers a `Coercible (forall (x :: Int). ()) (forall (x :: Quux Int). ())` constraint, which the constraint solver rejects (as it should). The original line does not use the same constraint-inference machinery, so it bypasses this step.
What can be done about this? It's tempting to have the original declaration generate this code instead:
```hs
instance Foo (Quux Int) where
bar = coerce @(forall (x :: Int). ())
@(forall (x :: Quux Int). ())
bar
```
Sadly, doing so would break a number of test cases that involve quantified constraints in instance contexts, such as `T15290`. See [`Note [GND and QuantifiedConstraints]`](https://gitlab.haskell.org/ghc/ghc/-/blob/9afd92512b41cf6c6de3a17b474d8d4bb01158c3/compiler/GHC/Tc/Deriv/Generate.hs#L1686-1773) for the full story. In order to make these test cases succeed (as a part of the fix for #15290), we employed an [ugly hack](132273f34e394bf7e900d0c15e01e91edd711890) where we split the `forall`s off of any types used to instantiate `coerce` in GND-generated code. But, as the example above demonstrates, this hack creates just as many problems as it solves.
@simonpj believes that this hack (and all of `Note [GND and QuantifiedConstraints]`) could be avoided. I don't quite understand his grand vision, so I'll let him comment here about what his vision entails.
Another similar example of this bug arising can be found in #18148. However, that issue is ensnared in a separate discussion about the roles of arguments to type classes, as the examples in #18148 crucially involve `ConstrainedClassMethods`. The underlying bug in this issue, on the other hand, does not fundamentally involve `ConstrainedClassMethods` in any way, so @simonpj and I have decided to track it separately here.