Skip to content

Separate `LPat` from `Pat` on the type-level by re-introducing `Located` only within GHC

Sebastian Graf requested to merge wip/wraploc into master

Since the Trees That Grow effort started, we had type LPat = Pat. This is so that SrcLocs 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 XPats everywhere! There are several functions which dont't cope with XPats 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.

Edited by Sebastian Graf

Merge request reports