[GHC] #11948: GHC forgets constraints

GHC ghc-devs at haskell.org
Mon Apr 18 09:55:24 UTC 2016


#11948: GHC forgets constraints
-------------------------------------+-------------------------------------
        Reporter:  crockeea          |                Owner:
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.0.2
       Component:  Compiler          |              Version:  7.10.3
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  GHC rejects       |  Unknown/Multiple
  valid program                      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 This is a very delicate example.  You have, roughly
 {{{
 class C a where
   op :: Int -> a

 instance C a => C [a] where ...

 f :: forall z. C [z] => blah
 f = ...(op 3 :: [z])....
 }}}
 So arising from the call to `op` we need to solve `C [z]`.  There are two
 ways to solve this:

 * From the `instance` declaration
 * From the `C [z] => ...` in the type signature for `f`

 If we choose the former, type checking will fail.  But generally speaking
 it is ''good'' to reduce class constraints using instance declarations.
 It's very odd to have a type signature that ''overlaps'' the instance.

 GHC makes some effort to get this "right", by prioritising solving against
 "givens", but it's a bit of a hopeless task.   After all, it might look
 like
 {{{
 f = ...(h (op 3))....
 }}}
 where after a great deal of constraint solving, functional dependencies,
 type function reduction, etc etc, we finally discover that `h`'s argument
 must have type `[z]`.

 In this particular case, GHC is trying to infer the most general type for
 `x`:
 {{{
   let x = bar sk :: Foo zq
 }}}
 Arising from `bar` we get the constraint `Bar (Foo (F sk)) (Foo sk)`.
 When inferring the most general type for `bar` we simplify the constraint
 as much as possible, using the class `instance` declaration.

 If you use `MonoLocalBinds` GHC does not attempt to generalise the type of
 `bar`.  So now the (still delicate) prioritisation scheme works, and the
 program compiles.  This why adding `TypeFamilies` helps: `TypeFamilies`
 implies `MonoLocalBinds`.

 Anyway the robust solution is to use the `instance` declaration to
 simplify the constraint for `bar`:
 {{{
 bug :: forall zq .
   (Bar (F zq) zq)
   => Foo (F zq) -> Foo zq
 }}}
 Maybe GHC should warn about type signatures that have constraints that are
 reducible with class `instance`s, since they are so fragile.  That would
 be a very worthwhile improvement.

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


More information about the ghc-tickets mailing list