Opened 3 years ago

Closed 3 years ago

#12594 closed bug (fixed)

DeriveAnyClass fails to derive some classes

Reported by: ivanm Owned by:
Priority: normal Milestone: 8.2.1
Component: Compiler Version: 8.0.1
Keywords: Generics Cc: leon.p.smith@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: tests/deriving/should_compile/T12594
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D2961
Wiki Page:

Description (last modified by hsyl20)

{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}

import Database.PostgreSQL.Simple
import GHC.Generics

data Foo = Foo { bar :: Int }
  deriving (Generic, ToRow)

This succeeds using ghci, but fails when trying to compile it using ghc with the following error message:

    • No instance for (ToRow Int)
        arising from the first field of ‘Foo’ (type ‘Int’)
      Possible fix:
        use a standalone 'deriving instance' declaration,
          so you can specify the instance context yourself
    • When deriving the instance for (ToRow Foo)

However, it works if I use instance ToRow Foo instead of relying upon DeriveAnyClass.

I've tried this with other types instead of Int, using newtype instead of data and having multiple fields in the datatype.

Change History (7)

comment:1 Changed 3 years ago by lpsmith

Cc: leon.p.smith@… added

comment:2 Changed 3 years ago by hsyl20

Description: modified (diff)

With DeriveAnyClass, GHC tries to infer the context for the instance. From compiler/typecheck/TcDeriv.hs:

-- Unfortunately, it is not clear how to determine the context (in case of
-- standard deriving; in standalone deriving, the user provides the context).
-- GHC uses the same heuristic for figuring out the class context that it uses for
-- Eq in the case of *-kinded classes, and for Functor in the case of
-- * -> *-kinded classes. That may not be optimal or even wrong. But in such
-- cases, standalone deriving can still be used.

Here it seems to infer instance ToRow Int => ToRow Foo , hence the error.

Maybe we should add the previous comment into the manual.

comment:3 Changed 3 years ago by simonpj

Yes, documenting this better would be a Jollly Good Thing.

Also pointing out that if the (necessarily fallible) heuristic for deducing a context fails, you can always us a "standalone deriving" declaration to specify the context yourself; it's a bit like adding a type signature.

Ryan or someone -- would you like to suggest a documentation patch?

Simon

comment:4 Changed 3 years ago by RyanGlScott

Keywords: Generics added

Alternatively, if we fix https://ghc.haskell.org/trac/ghc/ticket/9821#comment:8, then the code above will Just Work.

comment:5 Changed 3 years ago by RyanGlScott

Differential Rev(s): Phab:D2961
Milestone: 8.2.1
Status: newpatch

A WIP attempt at fixing this is at ​Phab:D2961.

comment:6 Changed 3 years ago by Ryan Scott <ryan.gl.scott@…>

In 639e702/ghc:

Refactor DeriveAnyClass's instance context inference

Summary:
Currently, `DeriveAnyClass` has two glaring flaws:

* It only works on classes whose argument is of kind `*` or `* -> *` (#9821).
* The way it infers constraints makes no sense. It basically co-opts the
  algorithms used to infer contexts for `Eq` (for `*`-kinded arguments) or
  `Functor` (for `(* -> *)`-kinded arguments). This tends to produce overly
  constrained instances, which in extreme cases can lead to legitimate things
  failing to typecheck (#12594). Or even worse, it can trigger GHC panics
  (#12144 and #12423).

This completely reworks the way `DeriveAnyClass` infers constraints to fix
these two issues. It now uses the type signatures of the derived class's
methods to infer constraints (and to simplify them). A high-level description
of how this works is included in the GHC users' guide, and more technical notes
on what is going on can be found as comments (and a Note) in `TcDerivInfer`.

Fixes #9821, #12144, #12423, #12594.

Test Plan: ./validate

Reviewers: dfeuer, goldfire, simonpj, austin, bgamari

Subscribers: dfeuer, thomie

Differential Revision: https://phabricator.haskell.org/D2961

comment:7 Changed 3 years ago by RyanGlScott

Resolution: fixed
Status: patchclosed
Test Case: tests/deriving/should_compile/T12594
Note: See TracTickets for help on using tickets.