#2806: Require bang-patterns for unlifted bindings
---------------------------------+------------------------------------------
Reporter: simonpj | Owner:
Type: feature request | Status: new
Priority: normal | Milestone: 6.12.1
Component: Compiler | Version: 6.8.3
Severity: normal | Resolution:
Keywords: | Difficulty: Unknown
Testcase: | Os: Unknown/Multiple
Architecture: Unknown/Multiple |
---------------------------------+------------------------------------------
Comment (by simonpj):
Just to record an email exchange.
Ian Lynagh:
{{{
It looks like TcBinds.checkStrictBinds is the place to do it.
If we have where clauses
where (b, I# a) = ...
where (b, I# !a) = ...
then we respectively get
mbind = <(b, GHC.Types.I# a) = ...>
mbind = <(b, GHC.Types.I# !a) = ...>
mono_tys = [(), GHC.Prim.Int#]
mono_tys = [(), GHC.Prim.Int#]
but where I get stuck is trying to match up the types with the bangs (or
lack of bangs). One option would be to walk over mbind, but that feels
rather hackish - especially as it's a bag rather than a list! Another
might be to put a boolean for the presence or absence of a bang in the
MonoBindInfo, and then to pair it with the type when making mono_tys.
}}}
Simon PJ replies:
{{{
| It looks like TcBinds.checkStrictBinds is the place to do it.
I agree.
| If we have where clauses
| where (b, I# a) = ...
| where (b, I# !a) = ...
Whoa! I think this is *not* what's proposed. Suppose we have
let (x, !y) = e in ...
This is *not* evaluated strictly. Rather, if 'x' is evaluated,
the pattern is matched, and hence y is evaluated at that moment.
Similarly if 'y' is evaluated, but that makes no difference.
Having a bang on the 'y' doesn't force strict evaluation of the pattern.
In contrast, if we have
let (x, I# y) = e in ..
then we *must* evaluate the whole let strictly (because y:Int#)
so we demand a bang on the whole pattern not on the 'y'.
So we should have written
let !(x, I# y) = in in ...
}}}
Ian says:
{{{
Oh, wow, you are right. So lifted and unlifted bindings wouldn't behave
uniformly after all:
foo1 = 'a'
where !(x, ~(y, !z)) = ('x', ('y', 1 `div` 0))
foo2 = 'a'
where !(x, ~(y, I# z)) = ('x', ('y', 1 `div` 0))
foo1 == 'a', but foo2 == _|_
Even more distressing is:
foo3 = 'a'
where !(x, ~(!y, !z)) = ('x', (1 `div` 0, (3 :: Int)))
foo4 = 'a'
where !(x, ~(!y, I# z)) = ('x', (1 `div` 0, (3 :: Int)))
Again foo3 == 'a' and foo4 == _|_, but in this case it is the evaluation
of !y that is the source of the _|_.
So perhaps ~p, where p contains an unlifted variable, should be rejected
too?
}}}
Simon says
{{{
Yes, absolutely it should. Let's do that at the same time.
I'm not 100% sure where the best place is. Presumably in TcPat, since
\~(x, I# y) -> ...
should also be rejected.
But when checking a ~pattern, we don't have conveniently to hand
the variables bound.
I suspect the easiest thing is going to be in
tc_pat (LazyPat ...)
to do (getPatBinders pat') and check for un-lifted types.
}}}
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2806#comment:4>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs