Opened 8 years ago

Closed 7 years ago

Last modified 3 years ago

#5884 closed bug (fixed)

GHC panics while trying to derive a Generic instance for Complex a

Reported by: mux Owned by: dreixel
Priority: normal Milestone:
Component: Compiler Version: 7.4.1
Keywords: Generics Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Compile-time crash Test Case: generics/T5884
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description (last modified by mux)

Using the StandaloneDeriving and DeriveGeneric extensions, GHC panics when deriving a Generic instance for Complex a with the following error:

GHCi, version 7.4.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( TestCase.hs, interpreted )
ghc: panic! (the 'impossible' happened)
  (GHC version 7.4.1 for x86_64-unknown-freebsd):
	tcTyVarDetails
    ( a{tv ahY} [tv] :: ghc-prim:GHC.Prim.*{(w) tc 34d} )

Attachments (1)

TestCase.hs (131 bytes) - added by mux 8 years ago.
The test case demonstrating the problem

Download all attachments as: .zip

Change History (11)

Changed 8 years ago by mux

Attachment: TestCase.hs added

The test case demonstrating the problem

comment:1 Changed 8 years ago by mux

Description: modified (diff)

comment:2 Changed 8 years ago by mux

I should have said that GHC crashes similarly, since the output I gave shows that it was produced using GHCi (the "interpreted" bit). I initially thought the two error messages were identical but there's a single letter difference: ahY becomes ahZ. For the sake of completeness, here is the error I get using ghc --make on the same test case with a dummy main function:

[1 of 1] Compiling Main             ( TestCase.hs, TestCase.o )
ghc: panic! (the 'impossible' happened)
  (GHC version 7.4.1 for x86_64-unknown-freebsd):
	tcTyVarDetails
    ( a{tv ahZ} [tv] :: ghc-prim:GHC.Prim.*{(w) tc 34d} )

comment:3 Changed 8 years ago by dreixel

Owner: set to dreixel

Thanks for the report. This is definitely a bug.

Initially I was thinking this was happening because Complex is an abstract datatype, but from what I can see it actually isn't, since its :+: constructor is exported. So maybe it's the strictness annotations. I'll investigate.

comment:4 in reply to:  3 ; Changed 8 years ago by simonpj

difficulty: Unknown

Replying to dreixel:

Thanks for the report. This is definitely a bug.

Initially I was thinking this was happening because Complex is an abstract datatype, but from what I can see it actually isn't, since its :+: constructor is exported. So maybe it's the strictness annotations. I'll investigate.

Any progress?

Simon

comment:5 in reply to:  4 Changed 8 years ago by dreixel

Replying to simonpj:

Any progress?

I'm planning to work on generics at the Utrecht hackathon (20--22 April), and then I'll look at this too. Is that ok, or would you like to have this particular bug fixed sooner?

comment:6 Changed 8 years ago by guest

I just ran into the same issue. The following conditions are required to reproduce:

  • the type we are trying to derive must be defined in a different module
  • that module must be compiled, not interpreted
  • the type we are trying to derive must have at least one non-phantom type variable argument

In short if we define these types in a module:

data A = A Int
data X a = X Int
data Y a = Y a

Compile this module and then import it into another module and derive some instances:

deriving instance Generic A   -- works
deriving instance Generic (X a)   -- works
deriving instance Generic a => Generic (X a) -- works
deriving instance Generic a => Generic (Y a) -- panic
deriving instance Generic (Y a) -- panic

data Z a = Z a
deriving instance Generic a => Generic (Z a) -- works
deriving instance Generic (Z a) -- works

I created a custom GHC API client to get a backtrace from the panic, but that doesn't seem particularly helpful:

*** Exception (reporting due to +RTS -xc): (THUNK_2_0), stack trace: 
  TcInteract.solve_loop,
  called from TcInteract.solveInteract,
  called from TcRnDriver.simplifyTop,
  called from TcRnDriver.tcRnSrcDecls,
  called from HscMain.Typecheck-Rename,
  called from Main.main,
  called from Main.CAF
Segmentation fault

comment:7 Changed 7 years ago by guest

A variable given to isTouchableMetaTyVar_InRange is a TyVar instead of the expected TcTyVar. For example, for this test program (Main.hs):

{-# LANGUAGE StandaloneDeriving, DeriveGeneric #-}

import GHC.Generics

{- case (a)
  import Data.Complex
-}

{- case (b)
  infix  6  :+
  data Complex a = a :+ a
-}

deriving instance Generic (Complex theVARIABLE)

main = putStrLn "test"

Uncommenting (a) to use Data.Complex a:

$ inplace/bin/ghc-stage2 -fforce-recomp Main.hs
[1 of 1] Compiling Main             ( Main.hs, Main.o )
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_c
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_c
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_g
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_g
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_n
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_n
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_r
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_r
isTouchableMetaTyVar call @ TcInteract.lhs:474 for a
isTouchableMetaTyVar call @ TcInteract.lhs:475 for theVARIABLE
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for a
ghc-stage2: panic! (the 'impossible' happened)
  (GHC version 7.5.20120420 for x86_64-unknown-linux):
    ASSERT failed!
    file compiler/typecheck/TcSMonad.lhs line 1221 a{tv ahY} [tv]

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

Uncommenting (b) to use our own Complex a:

$ inplace/bin/ghc-stage2 -fforce-recomp Main.hs
[1 of 1] Compiling Main             ( Main.hs, Main.o )
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_c
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_c
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_g
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_g
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_n
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_n
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_r
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_r
isTouchableMetaTyVar call @ TcInteract.lhs:482 for c_o
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for c_o
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_u
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_u
isTouchableMetaTyVar call @ TcInteract.lhs:482 for i_y
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for i_y
isTouchableMetaTyVar call @ TcInteract.lhs:482 for c_v
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for c_v
isTouchableMetaTyVar call @ TcInteract.lhs:482 for c_h
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for c_h
isTouchableMetaTyVar call @ TcInteract.lhs:482 for c_d
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for c_d
isTouchableMetaTyVar call @ TcInteract.lhs:474 for p_f
isTouchableMetaTyVar call @ TcInteract.lhs:475 for x
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for p_f
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for x
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_ts
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_ts
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tw
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tw
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tB
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tB
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tE
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tE
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tC
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tC
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tG
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tG
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tJ
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tJ
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tH
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tH
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tx
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tx
isTouchableMetaTyVar call @ TcInteract.lhs:482 for t_tt
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tt
isTouchableMetaTyVar call @ TcInteract.lhs:474 for t_tv
isTouchableMetaTyVar call @ TcInteract.lhs:475 for x
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for t_tv
isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for x
Linking Main ...

The debugging output is just 'trace' calls inserted at the call sites of isTouchableMetaTyVar and isTouchableMetaTyVar_InRange (diffs against the HEAD follow, reported line numbers may be wrong if you have local modifications):

TcInteract.lhs diff:

diff --git a/compiler/typecheck/TcInteract.lhs b/compiler/typecheck/TcInteract.lhs
index a2e0b99..fa4a630 100644
--- a/compiler/typecheck/TcInteract.lhs
+++ b/compiler/typecheck/TcInteract.lhs
@@ -471,15 +471,15 @@ trySpontaneousSolve workItem@(CTyEqCan { cc_flavor = gw
   | isGivenOrSolved gw
   = return SPCantSolve
   | Just tv2 <- tcGetTyVar_maybe xi
-  = do { tch1 <- isTouchableMetaTyVar tv1
-       ; tch2 <- isTouchableMetaTyVar tv2
+  = do { tch1 <- trace ("isTouchableMetaTyVar call @ TcInteract.lhs:474 for "++(showSDoc (ppr tv1))) (isTouchableMetaTyVar tv1)
+       ; tch2 <- trace ("isTouchableMetaTyVar call @ TcInteract.lhs:475 for "++(showSDoc (ppr tv2))) (isTouchableMetaTyVar tv2)
        ; case (tch1, tch2) of
            (True,  True)  -> trySpontaneousEqTwoWay d gw tv1 tv2
            (True,  False) -> trySpontaneousEqOneWay d gw tv1 xi
            (False, True)  -> trySpontaneousEqOneWay d gw tv2 (mkTyVarTy tv1)
 	   _ -> return SPCantSolve }
   | otherwise
-  = do { tch1 <- isTouchableMetaTyVar tv1
+  = do { tch1 <- trace ("isTouchableMetaTyVar call @ TcInteract.lhs:482 for "++(showSDoc (ppr tv1))) (isTouchableMetaTyVar tv1)
        ; if tch1 then trySpontaneousEqOneWay d gw tv1 xi
                  else do { traceTcS "Untouchable LHS, can't spontaneously solve workitem:" $
                            ppr workItem 
@@ -1935,8 +1935,8 @@ matchClassInst inerts clas tys loc
                                , cc_flavor = fl })
        | isGiven fl
        = ASSERT( clas_g == clas )
-         case tcUnifyTys (\tv -> if isTouchableMetaTyVar_InRange untch tv && 
-                                    tv `elemVarSet` tyVarsOfTypes tys
+         case tcUnifyTys (\tv -> if (trace ("isTouchableMetaTyVar_InRange call @ TcInteract.lhs:1938 for "++(showSDoc (ppr tv))) (isTouchableMetaTyVar_InRange untch tv && 
+                                    tv `elemVarSet` tyVarsOfTypes tys))
                                  then BindMe else Skolem) tys sys of
        -- We can't learn anything more about any variable at this point, so the only
        -- cause of overlap can be by an instantiation of a touchable unification

TcSimplify.lhs diff:

diff --git a/compiler/typecheck/TcSimplify.lhs b/compiler/typecheck/TcSimplify.lhs
index 26d4c9f..24a1125 100644
--- a/compiler/typecheck/TcSimplify.lhs
+++ b/compiler/typecheck/TcSimplify.lhs
@@ -1149,7 +1149,7 @@ getSolvableCTyFunEqs untch cts
                           , cc_rhs = xi })
       | Just tv <- tcGetTyVar_maybe xi      -- RHS is a type variable
 
-      , isTouchableMetaTyVar_InRange untch tv
+      , trace ("isTouchableMetaTyVar_InRange call @ TcSimplify.lhs:1152 for "++(showSDoc (ppr tv))) (isTouchableMetaTyVar_InRange untch tv)
            -- And it's a *touchable* unification variable
 
       , typeKind xi `tcIsSubKind` tyVarKind tv
@@ -1297,7 +1297,7 @@ defaultTyVar :: TcsUntouchables -> TcTyVar -> TcS Cts
 -- whatever, because the type-class defaulting rules have yet to run.
 
 defaultTyVar untch the_tv 
-  | isTouchableMetaTyVar_InRange untch the_tv
+  | trace ("isTouchableMetaTyVar_InRange call @ TcSimplify.lhs:1300 for "++(showSDoc (ppr the_tv))) (isTouchableMetaTyVar_InRange untch the_tv)
   , not (k `eqKind` default_k)
   = tryTcS $ -- Why tryTcS? See Note [tryTcS in defaulting]
     do { let loc = CtLoc DefaultOrigin (getSrcSpan the_tv) [] -- Yuk
@@ -1353,7 +1353,7 @@ findDefaultableGroups (ctxt, default_tys, (ovl_strings, extended_defaults))
     is_defaultable_group ds@((_,tv):_)
         = let b1 = isTyConableTyVar tv	-- Note [Avoiding spurious errors]
               b2 = not (tv `elemVarSet` bad_tvs)
-              b3 = isTouchableMetaTyVar_InRange untch tv 
+              b3 = trace ("isTouchableMetaTyVar_InRange call @ TcSimplify.lhs:1356 for "++(showSDoc (ppr tv))) (isTouchableMetaTyVar_InRange untch tv )
               b4 = defaultable_classes [cc_class cc | (cc,_) <- ds]
           in (b1 && b2 && b3 && b4)
           {- pprTrace "is_defaultable_group" (vcat [ text "isTyConable   " <+> ppr tv <+> ppr b1 

TcSMonad.lhs diff:

diff --git a/compiler/typecheck/TcSMonad.lhs b/compiler/typecheck/TcSMonad.lhs
index b3a64e3..5d3abf8 100644
--- a/compiler/typecheck/TcSMonad.lhs
+++ b/compiler/typecheck/TcSMonad.lhs
@@ -1214,7 +1214,7 @@ pprEq ty1 ty2 = pprType $ mkEqPred ty1 ty2
 isTouchableMetaTyVar :: TcTyVar -> TcS Bool
 isTouchableMetaTyVar tv 
   = do { untch <- getUntouchables
-       ; return $ isTouchableMetaTyVar_InRange untch tv } 
+       ; return $ (trace ("isTouchableMetaTyVar_InRange call @ TcSMonad.lhs for "++(showSDoc (ppr tv))) (isTouchableMetaTyVar_InRange untch tv)) } 
 
 isTouchableMetaTyVar_InRange :: TcsUntouchables -> TcTyVar -> Bool 
 isTouchableMetaTyVar_InRange (untch,untch_tcs) tv 

comment:8 Changed 7 years ago by simonpj

Resolution: fixed
Status: newclosed

Fixed by

commit 9e3171c632d200ae1b259dd3501fa6f6d9ac3278
Author: Simon Peyton Jones <simonpj@microsoft.com>
Date:   Thu Apr 26 14:39:59 2012 +0100

    Make the RHS of a generic FamInst use the same type variables as the LHS!

 compiler/typecheck/TcGenGenerics.lhs |   22 ++++++++++++----------
 1 files changed, 12 insertions(+), 10 deletions(-)

The problem was that in tc_mkRepTy you were using dataConOrigArgTys to get the argument types of the data con. Now these may or may not be identical with the tyConTyVars of the parent TyCon. (They used to be the same, but it's a fragile assumption, and turns out not to be so here.)

The solution is simple: use dataConInstOrigArgTys to instantiate the data constructor's type. That means passing a list of arg types to tc_mkRepTy, which in turn may get us on the way to #5936.

Anyway this one works now.

comment:9 Changed 7 years ago by simonpj

Test Case: generics/T5884

comment:10 Changed 3 years ago by RyanGlScott

Keywords: Generics added
Note: See TracTickets for help on using tickets.