tcInferRho muddies the waters
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 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.
Trac metadata
Trac field | Value |
---|---|
Version | 7.9 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |