Separate `LPat` from `Pat` on the type-level by re-introducing `Located` only within GHC
Since the Trees That Grow effort started, we had type LPat = Pat
.
This is so that SrcLoc
s would only be annotated in GHC's AST, which is
the reason why all GHC passes use the extension constructor XPat
to
attach source locations. See #15495 for the design discussion behind
that.
But now suddenly there are XPat
s everywhere!
There are several functions which dont't cope with XPat
s by either
crashing (hsPatType
) or simply returning incorrect results
(collectEvVarsPat
).
This issue was raised in #17330 (closed). I also came up with a rather clean and type-safe solution to the problem: We define
type family XRec p (f :: * -> *) = r | r -> p f
type instance XRec (GhcPass p) f = Located (f (GhcPass p))
type instance XRec TH f = f p
type LPat p = XRec p Pat
This is a rather modular embedding of the old "ping-pong" style, while
we only pay for the Located
wrapper within GHC. No ping-ponging in
a potential Template Haskell AST, for example. Yet, we miss no case
where we should've handled a SrcLoc
: hsPatType
and
collectEvVarsPat
are not callable at an LPat
.
Also, this gets rid of one indirection in Located
variants:
Previously, we'd have to go through XPat
and Located
to get from
LPat
to the wrapped Pat
. Now it's just Located
again.
Thus we fix #17330 (closed).
The corresponding solution on the wiki page is solution D.