[GHC] #11700: pattern match bug
GHC
ghc-devs at haskell.org
Mon Jun 13 22:18:11 UTC 2016
#11700: pattern match bug
-------------------------------------+-------------------------------------
Reporter: TobyGoodwin | Owner:
Type: bug | Status: closed
Priority: normal | Milestone:
Component: Compiler (Type | Version: 7.10.3
checker) |
Resolution: fixed | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
| typecheck/should_compile/T11700,
| ExPat, ExPatFail
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Changes (by simonpj):
* testcase: => typecheck/should_compile/T11700, ExPat, ExPatFail
* status: new => closed
* resolution: => fixed
Comment:
Well that has been lurking a long time.
It was caused by the fact that when the pattern binds dictionaries (which
this one does), we make an implication constraint, and bump the `TcLevel`.
Normally that doesn't happen because GHC complains about a pattern binding
that binds existential variables. But this one doesn't! It only binds
constraints!
Anyway it demonstrated to me that the way we were dealing with
existentials in pattern bindings was all wrong... better to ''use'' the
machinery of implication constraints, rather than cut across it. Here's
the new method (a Note in `TcBinds`). Much nicer! And it actually allows
more programs too.
{{{
{- Note [Existentials in pattern bindings]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider (typecheck/should_compile/ExPat):
data T where
MkT :: Integral a => a -> Int -> T
and suppose t :: T. Which of these pattern bindings are ok?
E1. let { MkT p _ = t } in <body>
E2. let { MkT _ q = t } in <body>
E3. let { MkT (toInteger -> r) _ = t } in <body>
Well (E1) is clearly wrong becuase the existential 'a' escapes.
What type could 'p' possibly have?
But (E2) is fine, despite the existential pattern, because
q::Int, and nothing escapes.
Even (E3) is fine. The existential pattern binds a dictionary
for (Integral a) which the view pattern can use to convert the
a-valued field to an Integer, so r :: Integer.
An easy way to see all three is to imagine the desugaring.
For (2) it would look like
let q = case t of MkT _ q' -> q'
in <body>
We typecheck pattern bindings as follows:
1. In tcLhs we bind q'::alpha, for each varibable q bound by the
pattern, where q' is a fresh name, and alpha is a fresh
unification variable; it will be the monomorphic verion of q that
we later generalise
It's very important that these fresh unification variables
alpha are born here, not deep under implications as would happen
if we allocated them when we encountered q during tcPat.
2. Still in tcLhs, we build a little environment mappting "q" ->
q':alpha, and pass that to tcLetPet.
3. Then tcLhs invokes tcLetPat to typecheck the patter as usual:
- When tcLetPat finds an existential constructor, it binds fresh
type variables and dictionaries as usual, and emits an
implication constraint.
- When tcLetPat finds a variable (TcPat.tcPatBndr) it looks it up
in the little environment, which should always succeed. And
uses tcSubTypeET to connect the type of that variable with the
expected type of the pattern.
And that's it! The implication constraints check for the skolem
escape. It's quite simple and neat, and more exressive than before
e.g. GHC 8.0 rejects (E2) and (E3).
}}}
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11700#comment:9>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list