[GHC] #9404: tcInferRho muddies the waters

GHC ghc-devs at haskell.org
Mon Aug 4 01:22:36 UTC 2014


#9404: tcInferRho muddies the waters
-------------------------------------+-------------------------------------
       Reporter:  goldfire           |                   Owner:  goldfire
           Type:  bug                |                  Status:  new
       Priority:  normal             |               Milestone:
      Component:  Compiler           |                 Version:  7.9
       Keywords:                     |        Operating System:
   Architecture:  Unknown/Multiple   |  Unknown/Multiple
     Difficulty:  Unknown            |         Type of failure:
     Blocked By:                     |  None/Unknown
Related Tickets:                     |               Test Case:
                                     |                Blocking:
                                     |  Differential Revisions:
-------------------------------------+-------------------------------------
 In trying to understand the algorithm implemented in !TcExpr, I've spent
 some time examining `tcInferRho`. I conjecture that this function is
 superfluous and should be removed, in favor of `tcInfer . tcExpr`. Some of
 these thoughts were first written up in [http://www.haskell.org/pipermail
 /ghc-devs/2014-July/005733.html this thread].

 After a considerable amount of staring, I've actually found a misbehavior
 caused by the current implementation. `tcInferRho` calls `tcInfExpr`,
 which has only 3 special cases before calling `tcInfer . tcExpr`: for
 variables, parentheses, and application. I was first drawn into this
 problem because these three cases seem woefully insufficient for the
 problem at hand. I was surprised how such a paucity of cases could have
 survived without causing havoc, if indeed `tcInferRho` were necessary at
 all. For example, only normal (prefix) application is handled; infix
 application is missing.

 In looking at differences between `tcInferApp` (which is called from the
 application case of `tcInfExpr`) and `tcApp` (called from `tcExpr`), I saw
 that the former doesn't have a special case for `seq` while the latter
 does. And, indeed, this difference is exploitable.

 This compiles fine:
 {{{
 foo _ = case () `seq` (# #) of (# #) -> ()
 }}}

 This does not:
 {{{
 foo _ = case seq () (# #) of (# #) -> ()
 }}}

 which produces

 {{{
 Scratch.hs:15:21:
     Kind incompatibility when matching types:
       b0 :: *
       (# #) :: #
     In the second argument of ‘seq’, namely ‘(##)’
     In the expression: seq () (##)
 }}}

 Looking at the code, this behavior is expected, because the first version
 of the code calls into `tcInfer . tcExpr`, which special-cases `seq`,
 while the second is caught by `tcInferApp`, which doesn't have the special
 case. The above example shows that this isn't just a theoretical concern
 about code cleanup!

 This all leads to another question: Why special-case `seq` at all? !MkId
 tells me that

 {{{
 seq :: forall (a :: *) (b :: *). a -> b -> b
 }}}

 Why isn't it

 {{{
 seq :: forall (a :: *) (b :: OpenKind). a -> b -> b
 }}}

 With the second type, I would imagine that `seq` wouldn't need a special
 case in the type-checker. Is there something wrong with the second type
 for `seq`?

 I'll post more thoughts to this ticket as I continue to explore.

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


More information about the ghc-tickets mailing list