#2748: Fundep-laden code compiled and ran fine in 6.8, fails in 6.10
---------------------------------+------------------------------------------
    Reporter:  sedillard         |        Owner:                  
        Type:  bug               |       Status:  closed          
    Priority:  normal            |    Milestone:                  
   Component:  Compiler          |      Version:  6.10.1          
    Severity:  normal            |   Resolution:  invalid         
    Keywords:                    |   Difficulty:  Unknown         
    Testcase:                    |           Os:  Unknown/Multiple
Architecture:  Unknown/Multiple  |  
---------------------------------+------------------------------------------
Changes (by simonpj):

  * status:  new => closed
  * difficulty:  => Unknown
  * resolution:  => invalid

Old description:

> I was kindly alerted by Ian Lynagh that some code of mine on hackage was
> causing 6.10-rc1 to fail to terminate. This code compiles and runs find
> on 6.8. Instead of diverging, 6.10.1 raises a type error. I've made a
> test case, and I'm creating this ticket to figure out what's going in. Is
> it,
>
> A) The code is incorrect and 6.8 was erroneously accepting it, and only
> by luck producing a valid program
>
> B) The code is correct and 6.10.1's typechecker is being overly
> conservative.
>
> At the core is overlapping instances. I've spent considerable effort
> removing them from the library, because I can't just look at the code and
> say for certain "this will never overlap with that" because its too
> complicated. Overlap errors become the users problem, I myself having
> been bitten by them many times as a user of my own library. The solution
> is to do without overlapping instances. The types of my instances then go
> from something nice like
>
> {{{
> instance (A t) => C t
> instance (B t) => C t --overlap
> }}}
>
> to something nasty like
>
> {{{
> instance (A (T (T x))) => C (T (T x))
> instance (B (T (T (T x)))) => C (T (T (T x))) --no overlap
> }}}
>
> It's uglier for me to read and write but ultimately better for the user
> because I've eliminated a category of errors.  If the compiler will let
> me, I try to abbreviate 'T (T (T x)))' to 't' in the instance head, but
> I'm not always able to because 't' is more general than 'T (T (T x)))'.
> I'm not entirely sure how that factors into things. To see what I'm
> talking about, compile the attached file and look for the error that says
> {{{Couldn't match expected type `vmt' against inferred type `vv :. (b' :.
> v)' `vmt' is a rigid type variable...}}}. It has something to do with
> functional dependencies. The fundep involved demands that 'vmt' be of the
> type 'x :. y :. z :. etc' but in this particular case it's so verbose I
> just call it 'vmt'. 6.8 lets me do that. 6.10 doesn't. Who's right?

New description:

 I was kindly alerted by Ian Lynagh that some code of mine on hackage was
 causing 6.10-rc1 to fail to terminate. This code compiles and runs find on
 6.8. Instead of diverging, 6.10.1 raises a type error. I've made a test
 case, and I'm creating this ticket to figure out what's going in. Is it,

 A) The code is incorrect and 6.8 was erroneously accepting it, and only by
 luck producing a valid program

 B) The code is correct and 6.10.1's typechecker is being overly
 conservative.

 At the core is overlapping instances. I've spent considerable effort
 removing them from the library, because I can't just look at the code and
 say for certain "this will never overlap with that" because its too
 complicated. Overlap errors become the users problem, I myself having been
 bitten by them many times as a user of my own library. The solution is to
 do without overlapping instances. The types of my instances then go from
 something nice like

 {{{
 instance (A t) => C t
 instance (B t) => C t --overlap
 }}}

 to something nasty like

 {{{
 instance (A (T (T x))) => C (T (T x))
 instance (B (T (T (T x)))) => C (T (T (T x))) --no overlap
 }}}

 It's uglier for me to read and write but ultimately better for the user
 because I've eliminated a category of errors.  If the compiler will let
 me, I try to abbreviate 'T (T (T x)))' to 't' in the instance head, but
 I'm not always able to because 't' is more general than 'T (T (T x)))'.
 I'm not entirely sure how that factors into things. To see what I'm
 talking about, compile the attached file and look for the error that says
 {{{
 Couldn't match expected type `vmt' against inferred type `vv :. (b' :. v)'
 `vmt' is a rigid type variable...
 }}}
 It has something to do with functional dependencies. The fundep involved
 demands that 'vmt' be of the type 'x :. y :. z :. etc' but in this
 particular case it's so verbose I just call it 'vmt'. 6.8 lets me do that.
 6.10 doesn't. Who's right?

Comment:

 This is a scarily complicated piece of code.  I wonder if would look
 simpler with type functions?

 Still I took a look. I can see this:
 {{{
 -- Line 147-ish
 class Map a b u v | u -> a, v -> b, b u -> v, a v -> u where ...
 instance Map a b (a':.u) (b':.v)
       => Map a b (a:.a':.u) (b:.b':.v) where ...

 -- Line 68-ish
 instance
     (...
     ,Map (a:.a:.a:.v) vv ((a:.a:.a:.v):.(a:.a:.a:.v):.m) vmt
     ...)  where ...

     )
      =>
     Det' a ((a:.a:.a:.v):.(a:.a:.a:.v):.(a:.a:.a:.v):.m)
 }}}
 Consider this simpler version:
 {{{
   class C a b | a->b
   instance C Int Bool
   f :: C Int x => ...
 }}}
 GHC rejects the type ignature for 'f' because 'x' must be `Bool`.  It's
 the same in an instance declaration
 {{{
   instance C Int x => ...
 }}}
 And that's what you have here. The fundep `b u -> v` in class `Map`
 together with the instance declaration says that in any constraint
 {{{
    Map ... tb (ta:ta':tu) vmt
 }}}
 then `vmt` must be of form `(tb:tb':tv)`.   But in your example it isn't.

 Changing the instance decl to
 {{{
 instance
     (...
     ,Map (a:.a:.a:.v) vv ((a:.a:.a:.v):.(a:.a:.a:.v):.m)
          (vv :. vmt1 :. vmt2)
     ...)  where ...

     )
      =>
     Det' a ((a:.a:.a:.v):.(a:.a:.a:.v):.(a:.a:.a:.v):.m)
 }}}
 and replacing `vmt` by `(vv:.vmt1:.vmt2)` in the code, makes the error go
 away.

 In short, when you use a type variable like `vmt` in a type signature, GHC
 assumes you mean a type `variable` and checks that you do.   This is
 presumably a bug in 6.8.

 I've taken the opportunity to improve the error message to say which
 fundep is involved.  I'll close the bug though.

 Simon

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2748#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to