Suppose that I have this type family that throws a custom type error during compile time if the type passed to it is not a record:
type family IsRecord (a :: Type) where
...
Now I have this type class that has methods with default implementations, but requires that the type is a record, by adding the IsRecord
constraint:
class IsRecord a => Foo a where
foo :: Text
foo = "foo"
When trying to use it incorrectly, if we use it as a regular instance with a type that is not a record, it successfully fails to compile:
data Bar = Bar
instance Foo Bar -- error: Bar is not a record
But if I enable -XDeriveAnyClass
and add it to the deriving clause, this doesn't fail to compile, ignoring completely the constraint:
data Bar = Bar
deriving (Foo)
I understand that DeriveAnyClass
generates an empty instance declaration, which is what I'm doing on the first example, but still it doesn't throw the error. What's going on?
I'm using GHC 8.6.4
Wow! I was going to mark this as a duplicate of What is the difference between DeriveAnyClass
and an empty instance?, but it seems the behavior of GHC has changed since that question was asked and answered!
Anyway, if you ask -- either with :i
inside ghci or with -ddump-deriv
before starting ghci -- what the compiler has done, it's clear what the difference is in your case:
> :i Bar
data Bar = Bar -- Defined at test.hs:15:1
instance IsRecord Bar => Foo Bar -- Defined at test.hs:16:13
Indeed, if you change the non-DeriveAnyClass
version of your code to match, writing
instance IsRecord Bar => Foo Bar
instead of
instance Foo Bar
everything works fine. The details of how this instance context was chosen seem a bit complicated; you can read what the GHC manual has to say about it here, though I suspect the description there is either not quite precise or not complete, as I don't get the same answer the compiler does here if I strictly follow the rules stated at the documentation. (I suspect the true answer is that it writes the instance first, then just does the usual type inference thing and copies any constraints it discovers in that way into the instance context.)