[GHC] #12466: Typechecker regression: Inaccessible code in a type expected by the context

GHC ghc-devs at haskell.org
Thu Aug 25 16:08:25 UTC 2016


#12466: Typechecker regression: Inaccessible code in a type expected by the context
-------------------------------------+-------------------------------------
        Reporter:  RyanGlScott       |                Owner:
            Type:  bug               |               Status:  new
        Priority:  highest           |            Milestone:  8.0.2
       Component:  Compiler (Type    |              Version:  8.1
  checker)                           |
      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 ekmett):

 I think there is morally a difference between

 {{{#!hs
 class Foo a where
    foo :: (a ~ Int => a) -> a -> a
 }}}

 and your example which is more like

 {{{#!hs
 class Foo a where
    foo :: (a ~ Int) => a -> a -> a
 }}}

 in terms of if we should reject things once we know `a ~ Char`, and that
 hence `a ~ Int` can never happen.

 In the former you're given two arguments, one of which requires you to
 provide something impossible to use, and so simply cant be used, while in
 the latter you're required to implement a contradiction when you go to
 write `instance Foo Char`.

 Notice the polarity of the equality constraint. In the former it is in
 positive position. In the latter it is in negative position as usual.
 Finding a contradiction in negative position fits with Richard's intuition
 about if we should complain, but in positive position it simply means that
 argument is inaccessible, which is perfectly okay.

 Someone might pass it in in a more polymorphic setting where they don't
 know if the constraint could be satisfied or not, until the instance for
 Foo is selected, which is what is happening here.

 Today I usually hack around the latter by passing an explicit Dict for the
 constraint, so that I have the option to bring it into scope or not, and
 can carefully avoid GHC prematurely detonating upon discovering the
 contradiction

 {{{#!hs
 class Foo a where
    foo :: Dict (a ~ Int) -> a -> a -> a
 }}}

 but until now I haven't had to hack around it for the former -- and the
 explicit Dict-based solutions are much clunkier to both write, and for
 users to use in practice. (We used to use this approach to implement ex
 falso quodlibet in the `constraints` package, but now we just use `Any`
 directly as an uninhabitable initial `Constraint`.)

 > Currently

 {{{#!hs
 foo :: (Char ~ Int => Int) -> a -> a
 foo _ a2 = a2
 }}}

 > gives a similar message. Is that reasonable? The argument to foo can't
 be called.

 I'd personally think that that should be allowed, as silly as it looks in
 this very concrete case. `foo` itself doesn't care about the argument at
 all. The burden of complaining about the impossibility of what we can see
 locally would be `Int ~ Char` should fall on type checking the argument
 passed to `foo` at the call site, not to `foo`, and at that call site it
 may or may not be impossible as it may not know the `Int` part of the
 equation there.

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


More information about the ghc-tickets mailing list