[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