I would think that pattern synonyms for unlifted types should work, but with the same restrictions as normal patterns for unlifted types. That is, you can't use these patterns to define a global variable.
The problem with pattern P = 0# is that the wrapper it yields is $WP = 0# which is a top-level binding at an unboxed type. If P had any arguments, then $WP would be a function instead of a variable, and so it would be valid. So we could say that unboxed pattern synonyms are only allowed if they are either unidirectional or have arguments. But doesn't that sound a bit arbitrary?
Side question: is it even possible to change the definition of P to have an argument but still be unboxed? Something like pattern P x = (# 0#, x #) doesn't work, because unboxed tuples are not allowed in patterns.
Look at WwLib.mkWorkerArgs which deals with much the same issue. We just add a void argument to the wrapper avoid the top-level unboxed binding. I think we can do the same thing for pattern synonyms, no?
Hmm. mkWorkerArgs looks like quite the rabbit hole... does it make sense to figure out the plumbing for that, or is it good enough to just steal the basic idea and implement something similar for pattern synonyms that ensures there's always at least one argument (a synthetic () if need be) to pattern synonym wrapper functions returning unboxed values?
Never mind, I've figured out that last bit -- it's because in this case, $mPAT is used at type Int# -> Int# -> Int# -> Int#, so it's always going to be strict in both the cont and the fail arguments.
I'll change the code generator for matchers so that both cont and fail takes an extra () argument. Another problem, then, will be making the matcher polymorphic enough that its r type argument can be either * or #...
(and of course if $mPAT :: forall (r :: ?) is not kosher, we can just have two matchers, one $mPAT :: forall (r :: *) and one $mPAT# :: (forall r :: #), and just have the extra () arguments for cont/fail for the latter)
Yes, I've found voidPrimId/voidArgId meanwhile, and I have a working implementation pushed to wip/T9732 just now.
However, I had to split the matcher into two, since otherwise I can't decide when to have the extra arg, since the result type is completely unknown at matcher generation time. So for now, I've went with
Main.$mPAT :: forall r. GHC.Prim.Int# -> r -> r -> rMain.$m#PAT :: forall (r :: #). GHC.Prim.Int# -> (GHC.Prim.Void# -> r) -> (GHC.Prim.Void# -> r) -> r
so that takes care of using pattern synonyms when the result type is unlifted: both of these now compile lint-free, and give the expected behaviour:
f PAT = 42#g PAT = (42 :: Int)
So the only remaining TODO should be to add this extra Void# argument to the generated wrappers when there are no other arguments and the pattern type is unlifted.
Yes, I see. You don't know if the result is unlifted, but you DO know if cont has value args. (Which it does not in this case.)
I think you can just have the second of your two matchers, with forall (r :: ?). ..., something that is not possible in source Haskell, but which you can do in generated code I think.
A single open-kinded matcher works, yes, if we are OK with argument-free conts and all fails taking the extra Void# argument. I will redo my implementation for this design.
Implementation based on the discussion above is now pushed to wip/T9732. Also, now, patsyns in expression contexts are sometimes compiled into calls with a dummy Void# argument.
I think it's good enough to go into master but I'd prefer if Simon took a look at it first.
I have pushed a new version of the commit that applies cleanly to ghc-7.8 as a91a2af..0f1f3e1, please merge that.
Also, in the future, please try applying the patches in question at an earlier time, instead of discovering if they have problems so close to the freeze date.