Opened 9 years ago

Closed 9 years ago

#4528 closed bug (fixed)

stand-alone deriving sometimes fails for GADTs

Reported by: nestra Owned by:
Priority: normal Milestone: 7.2.1
Component: Compiler (Type checker) Version: 7.0.1
Keywords: deriving mechanism, GADTs Cc:
Operating System: Linux Architecture: x86_64 (amd64)
Type of failure: Compile-time performance bug Test Case: deriving/should_fail/T4528, deriving/should_run/T4528a
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Consider the following module

{-# LANGUAGE GADTs, StandaloneDeriving #-}
module Foo where

data Foo a where
  A, B :: Foo Int

deriving instance Enum (Foo a)

Loading it into GHCi causes the following message:

ghc: panic! (the 'impossible' happened)
  (GHC version 7.0.1 for x86_64-unknown-linux):
        maybe_is_tagToEnum_call.extract_constr_Ids

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

In the case of Bounded instead of Enum in the original code, it does not work either but the error message is more "even-tempered":

Foo.hs:7:1:
    Couldn't match type `a' with `Int'
      `a' is a rigid type variable bound by
          the instance declaration at Foo.hs:7:32
    In the expression: A
    In an equation for `minBound': minBound = A
    When typechecking the code for  `minBound'
      in a standalone derived instance for `Bounded (Foo a)':
      To see the code I am typechecking, use -ddump-deriv
    In the instance declaration for `Bounded (Foo a)'

Foo.hs:7:1:
    Couldn't match type `a' with `Int'
      `a' is a rigid type variable bound by
          the instance declaration at Foo.hs:7:32
    In the expression: B
    In an equation for `maxBound': maxBound = B
    When typechecking the code for  `maxBound'
      in a standalone derived instance for `Bounded (Foo a)':
      To see the code I am typechecking, use -ddump-deriv
    In the instance declaration for `Bounded (Foo a)'
Failed, modules loaded: none.

I suspect that this is also a bug, as it would be perfectly reasonable to have minBound and maxBound for a type such as Foo Int.

A similar deriving fails also for Read class, among those I tried.

Change History (4)

comment:1 Changed 9 years ago by simonpj

Thanks for pointing this out.

It's not reasonable to derive an Enum instance for a GADT. Consider

    data T a where
      T1 :: T Int
      T2 :: T Bool
      T3 :: T a

What would [T1 ..] be? Clearly not [T1,T2,T3] because that would be ill-typed. Perhaps [T1,T3] :: T Int? It is very far from clear. I have added a check to treat GADTs as non-enumerations.

The same holds for Bounded. After, all minBound for T should have type

minBoundT :: forall a. T a

but the minBound is T1, which doesn't have that type.

For Read things are less clear. In general the "standalone deriving" mechanism generates the boilerplate code and typechecks it; if it doesn't typecheck you get a complaint (see #3012). So the error messages for Read seem right. Situation is different for Enum because it uses the primop tagToEnum# which must be treated with care.

I'll commit a fix shortly.

Simon

comment:2 Changed 9 years ago by simonpj

Status: newmerge
Test Case: deriving/should_fail/T4528, deriving/should_run/T4528a

OK two patches. This one tightens up the defn of what can be enumerations.

Wed Dec 15 04:19:27 PST 2010  simonpj@microsoft.com
  * Tighten up what it means to be an "enumeration data constructor"
  
  See Note [Enumeration types] in TyCon, and comments in Trac #4528

    M ./compiler/iface/BuildTyCl.lhs -2 +6
    M ./compiler/types/TyCon.lhs -1 +11

As a result you now get

T4528.hs:10:1:
    Can't make a derived instance of `Enum (Foo a)':
      `Foo' is not an enumeration type
      (an enumeration consists of one or more nullary, non-GADT constructors)
    In the stand-alone deriving instance for `Enum (Foo a)'

A second patch fixes a bug in the byte code generator, whereby it didn't know that an enumeration can (in GHC) have a phantom argument:

data T a = A | B | C

This crashes 7.0.1 when loaded into GHCi. Fixed by

Wed Dec 15 12:18:17 GMT 2010  simonpj@microsoft.com
  * Allow enumerations to have phantom arguments.
  
  The bytecode generator was being too eager.
  Fixes Trac #4528, or rather, a near variant.

    M ./compiler/ghci/ByteCodeGen.lhs -2 +2

Both have tests; both could be merged.

Simon

comment:3 Changed 9 years ago by igloo

Milestone: 7.0.3

comment:4 Changed 9 years ago by igloo

Resolution: fixed
Status: mergeclosed

Merged.

Note: See TracTickets for help on using tickets.