#4220 closed bug (fixed)
EmptyDataDecls + DeriveFunctor == Panic!
Reported by: | conal | Owned by: | simonpj |
---|---|---|---|
Priority: | normal | Milestone: | 7.0.1 |
Component: | Compiler | Version: | 6.12.3 |
Keywords: | Cc: | conal@…, black.meph@…, jules@… | |
Operating System: | Unknown/Multiple | Architecture: | Unknown/Multiple |
Type of failure: | Compile-time crash | Test Case: | deriving/should_compile/T4220 |
Blocked By: | Blocking: | ||
Related Tickets: | #4302 | Differential Rev(s): | |
Wiki Page: |
Description
I get "ghc: panic! (the 'impossible' happened)" from GHC 6.12.1 with a simple two-line program
{-# LANGUAGE EmptyDataDecls, DeriveFunctor #-} data Void a deriving Functor
Also on hpaste.
GHC says
ghc: panic! (the 'impossible' happened) (GHC version 6.12.1 for i386-apple-darwin): TcPat.checkArgs
I asked on the #ghc IRC room and learned that
ClaudiusMaximus: conal: ghc-6.12.3 here, same error. (GHC version 6.12.3 for x86_64-unknown-linux)
Change History (9)
comment:1 Changed 7 years ago by
comment:2 Changed 7 years ago by
Cc: | black.meph@… added |
---|---|
Version: | 6.12.1 → 6.12.3 |
If you check the referenced hpaste, you'll see that it also occurs on Windows builds.
comment:3 Changed 7 years ago by
Owner: | set to conal |
---|
comment:4 Changed 7 years ago by
Ah yes. I have a fix in my tree. Conal, did becoming the "owner" mean that you intended to submit a patch?
My fix generates a catch-all equation for fmap
fmap _ a = unsafeCoerce# a
in two cases:
- When there are no constructors
- When there are any constructors that don't mention the "active" type variable at all
The latter case is to catch a situation like this
data T a b = T1 b | T2 a | T3 a | T4 a | T5
The "active" type variable is the last one in type, "b" in this case. Here it seems a waste to pattern-match on T2-T5 (as the current 6.12 does).
Better to say
fmap f (T1 x) = T1 (f x) fmap _ a = unsafeCoerce# a
The coerce is necessary to change the type, of course.
Does that seem right?
There must be something similar for Foldable
and Traversable
, not just Functor
, and we'd better fix them at the same time:
- I believe the criterion is the same: that is, any data constructors whose argument types do not mention the active type variable can be treated uniformly with a no-op.
- I'm not sure what the code for a no-op for
Foldable
andTraversable
are. Can someone say, please?
Simon
comment:5 Changed 7 years ago by
Owner: | conal deleted |
---|
comment:6 Changed 7 years ago by
Milestone: | → 6.14.1 |
---|---|
Owner: | set to simonpj |
comment:7 Changed 7 years ago by
Cc: | jules@… added |
---|
For Foldable
it suffices to define foldMap
:
foldMap :: Monoid m => (a -> m) -> t a -> m
If you "don't have" anything of type a
either because it's an EmptyDataDecl or because it's a constructor which doesn't mention the type variable, then the only possible result is mempty
.
foldMap _ _ = mempty
That suffices to define an instance, but for efficiency(?) you could add the other methods directly.
fold :: Monoid m => t m -> m fold _ = mempty foldMap :: Monoid m => (a -> m) -> t a -> m foldMap _ _ = mempty foldr :: (a -> b -> b) -> b -> t a -> b foldr _ start _ = start foldl :: (a -> b -> a) -> a -> t b -> a foldl _ start _ = start foldr1 :: (a -> a -> a) -> t a -> a foldr1 _ _ = error "Foldable.foldr1" foldl1 :: (a -> a -> a) -> t a -> a foldl1 _ _ = error "Foldable.foldl1"
For Traversable
it suffices to define traverse
:
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
Similar reasoning - if you don't have any a
then you can't apply the function given, and there can be no applicative effects to consider because no value f b
can be constructed. So, rather like in the functor case, you do a constructor by constructor conversion, wrapped in pure
for no effects.
traverse _ (T2 a) = pure (T2 a) -- n.b. these two (T2 a) expressions are at a different type
By the same process as for Functor you might choose to go for the under-the-hood more efficient pure . unsafeCoerce#
, or alternatively you can "delegate" the efficiency hack to the Functor instance and use pure . fmap undefined
.
Does that all sound reasonable?
comment:8 Changed 7 years ago by
Resolution: | → fixed |
---|---|
Status: | new → closed |
Test Case: | → deriving/should_compile/T4220 |
In the end I did the simplest thing. Fixed by
Thu Aug 12 14:13:19 BST 2010 simonpj@microsoft.com * Fix Trac #4220 For deriving Functor, Foldable, Traversable with empty data cons I just generate a null equation f _ = error "urk" There are probably more lurking (eg Enum) but this will do for now.
Simon
comment:9 Changed 17 months ago by
Related Tickets: | → #4302 |
---|
commit 6efa3901fd6f1583fb654bd3659e88702dfd579a
Author: simonpj@microsoft.com <unknown> Date: Thu Aug 12 13:13:19 2010 +0000 Fix Trac #4220 For deriving Functor, Foldable, Traversable with empty data cons I just generate a null equation f _ = error "urk" There are probably more lurking (eg Enum) but this will do for now.
The following explicit instance works fine, though it's too bad we have to make the error case explicit, since Void can be covered exhaustively with no clauses.