[GHC] #9371: Overlapping type families, segafult

GHC ghc-devs at haskell.org
Mon Jul 28 09:32:09 UTC 2014


#9371: Overlapping type families, segafult
----------------------------------------+----------------------------------
              Reporter:  pingu          |            Owner:
                  Type:  bug            |           Status:  new
              Priority:  normal         |        Milestone:
             Component:  Compiler       |          Version:  7.8.3
            Resolution:                 |         Keywords:
      Operating System:  Linux          |     Architecture:  x86_64 (amd64)
       Type of failure:  Runtime crash  |       Difficulty:  Unknown
             Test Case:                 |       Blocked By:
              Blocking:                 |  Related Tickets:
Differential Revisions:                 |
----------------------------------------+----------------------------------
Changes (by simonpj):

 * cc: goldfire, dimitris@…, sweirich@…, nomeata, Conor.McBride@… (added)


Comment:

 Great bug!  I know exactly what is going on.

 There is a long-standing awkwardness in GHC’s implementation of newtype,
 described in `Note [Newtype eta]` in `TyCon`, which I reproduce below.
 The core of it comes down to this.  Consider
 {{{
 newtype Parser a = MkParser (IO a) derriving( Monad )
 }}}
 Do we have `(Monad Parser ~R Monad IO)`?  These are the types of the Monad
 dictionaries for Parser and IO resp.  In the olden days to implement
 Generalised Newtype Deriving (GND) we coerced directly between these
 dictionary types, so we really needed them to be ~R.  As a result, the
 axiom induced by the above newtype had to be
 {{{
         ax :: Parser ~R IO
 }}}
 and not
 {{{
         ax a :: Parser a  ~R  IO a
 }}}
 So we had to eta-reduce axioms.

 This is a royal pain.  And we have to do it for newtype instances too.
 See `Note [Eta reduction for data family axioms]` in `TcInstDcls`. And it
 turns out that the new, serious bug #9371 is directly attributable to this
 royal pain.

 Side note: our [http://research.microsoft.com/en-
 us/um/people/simonpj/papers/ext-f/ Safe coercions” paper] does not say in
 Section 2 how to deal with data/newtype instances.

 NOW, in our new story for GND, we never coerce between `Monad Parser` and
 `Monad IO`.  Instead we coerce the individual methods (Section 7 of the
 paper).  Why?   I think it’s because our roles are not higher-kinded, but
 we didn’t document the change. Does anyone else remember?  I think there
 were actually multiple reasons.

 However this change means that we DON’T need `(IO ~R Parser)` any more!
 Only `(IO ty  ~R  Parser ty)`.  So the reason for the eta reduction seems
 to have gone away.

 Do you agree?  If  so I could simplify GHC by removing the complicated eta
 stuff.  I would rather do that than fix #9371 by adding more complexity

 I see that this was actually proposed in #8503, but the thread diverged
 onto other matters.  Richard’s last comment:7 said “So we don't need eta-
 reduction as much as maybe we once did, but it's still useful.” but
 provided no evidence in support of this claim.

 I somehow think this is connected to #9123 but I can’t put my finger on
 why.

 Simon

 {{{
 Note [Newtype eta]
 ~~~~~~~~~~~~~~~~~~
 Consider
         newtype Parser a = MkParser (IO a) derriving( Monad )
 Are these two types equal (to Core)?
         Monad Parser
         Monad IO
 which we need to make the derived instance for Monad Parser.

 Well, yes.  But to see that easily we eta-reduce the RHS type of
 Parser, in this case to ([], Froogle), so that even unsaturated
 applications
 of Parser will work right.  This eta reduction is done when the type
 constructor is built, and cached in NewTyCon.  The cached field is
 only used in coreExpandTyCon_maybe.

 Here's an example that I think showed up in practice
 Source code:
         newtype T a = MkT [a]
         newtype Foo m = MkFoo (forall a. m a -> Int)

         w1 :: Foo []
         w1 = ...

         w2 :: Foo T
         w2 = MkFoo (\(MkT x) -> case w1 of MkFoo f -> f x)

 After desugaring, and discarding the data constructors for the newtypes,
 we get:
         w2 :: Foo T
         w2 = w1
 And now Lint complains unless Foo T == Foo [], and that requires T==[]

 This point carries over to the newtype coercion, because we need to
 say
         w2 = w1 `cast` Foo CoT

 so the coercion tycon CoT must have
         kind:    T ~ []
  and    arity:   0
 }}}

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9371#comment:3>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list