[GHC] #16322: "deriving newtype instance" generates an infinite loop
GHC
ghc-devs at haskell.org
Fri Feb 15 19:39:59 UTC 2019
#16322: "deriving newtype instance" generates an infinite loop
-------------------------------------+-------------------------------------
Reporter: paf31 | Owner: (none)
Type: bug | Status: infoneeded
Priority: normal | Milestone:
Component: Compiler | Version: 8.6.3
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by RyanGlScott):
Ah, I misinterpreted your comment—I thought that you were implying that
the code was infinitely looping at compile-time, not runtime. My
apologies.
The code that `deriving newtype instance C a b => C (X String a) (X String
b)` generates is expected behavior, as it turns out. From the
[https://downloads.haskell.org/~ghc/8.6.3/docs/html/users_guide/glasgow_exts.html
#extension-StandaloneDeriving users' guide section] on
`StandaloneDeriving`:
> The stand-alone syntax is generalised for newtypes in exactly the same
way that ordinary deriving clauses are generalised [...]. For example:
>
> {{{#!hs
> newtype Foo a = MkFoo (State Int a)
>
> deriving instance MonadState Int Foo
> }}}
>
> GHC always treats the //last// parameter of the instance (Foo in this
example) as the type whose instance is being derived.
In other words, the generated code will `coerce` underneath the last type
argument, and nothing more. In your example, you have:
{{{#!hs
class C a b | a -> b, b -> a where
c :: Proxy a -> Int
newtype X a b = X b
deriving newtype instance C a b => C (X String a) (X String b)
}}}
This will `coerce` from `X String b` to `b`, and nothing more. Because the
type of `c` happens to never mention the last type parameter of `C`, this
results in the "identity coercion" behavior you see with `-ddump-deriv`.
It's a bit strange, but there's a certain consistency to it. After all,
`deriving newtype instance C a b => C (X String a) (X String b)` could
mean three different things:
1. Coerce underneath `X String a` only.
2. Coerce underneath `X String b` only.
3. Coerce underneath `X String a` and `X String b`.
In general, if a multi-parameter type class has //n// type parameters,
then there are 2^//n//^ - 1 different potential choices of code to
generate. Since `deriving` clauses only `coerce` underneath the last type
parameter, `StandaloneDeriving` picks the same convention.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/16322#comment:4>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list