Refactor Anno type family and expcitly mark out annotation types in the AST.
The Anno
type family is currently used to attach exactprint meta data to SrcSpan
s via the XRec
wrapper type family:
type instance XRec (GhcPass p) a = GenLocated (Anno a) a
There is currently a plan to move this information directly into the syntax tree. However, this will be a major refactoring and has an indeterminate ETA. Meanwhile, these instances get in the way of other people trying to use TTG to define custom "passes" over the AST (like @fendor's WIP rework of !3866) and result in terrible type errors(https://paste.tomsmeding.com/PtDRKhYf).
There are a lot of instances of Anno
defined for general purpose types, like [..]
, Maybe ...
, (..,..)
, which might be used in many contexts in the AST, requiring different annotations for each. However, currently these are tied to a single context and will always be given a single type of exactprint annotations.
For example, the following instances of Anno
are OK, since they are defined for a specific kind of AST construct:
type instance Anno (RuleBndr (GhcPass p)) = SrcSpan
type instance Anno (RuleDecl (GhcPass p)) = SrcSpanAnnA
type instance Anno (DerivStrategy (GhcPass p)) = SrcSpan
However, some instances are for more generic types that might be used in different contexts:
-- For CompleteMatchSig
type instance Anno [LocatedN RdrName] = SrcSpan
type instance Anno [LocatedN Name] = SrcSpan
type instance Anno [LocatedN Id] = SrcSpan
[LocatedN Name]
is a very general purpose type that may occur in multiple places in the AST. We can easily imagine some kind of future
construct which would require a [Located Name]
field with a SrcSpanAnnA
annotation instead. However, Anno
implicitly ties it to the
current usage in CompleteMatchSig
, which means that this type cannot currently be used anywhere else without significant refactoring.
Then here are even more horrific instances of Anno
...
type instance Anno [LocatedA ((StmtLR (GhcPass pl) (GhcPass pr) (LocatedA (HsExpr (GhcPass pr)))))] = SrcSpanAnnL
type instance Anno [LocatedA ((StmtLR (GhcPass pl) (GhcPass pr) (LocatedA (HsCmd (GhcPass pr)))))] = SrcSpanAnnL
One way to fix this could be to define a newtype wrapper that has a phantom type that determines the type of the annotation:
newtype Annotated a x = Annotated { unAnnotate :: x }
type instance Anno (Annotated a x) = a
Then we can use Annotated SrcSpan [LocatedN Name]
when we don't need additional annotations, Annotated SrcSpanAnnA [LocatedN Name]
when we need [LocatedN Name]
annotated with list annotations and so on.
I also propose the following refactoring to (Scratch this idea, it doesn't seem to be worth it)GenLocated
, since we always need a SrcSpan
regardless of the annotation type:
data GenLocated a l e = L a l e
type instance XRec (GhcPass p) a = GenLocated (Anno a) SrcSpan a
type LocatedA = GenLocated AnnListItem SrcSpan
type LocatedN = GenLocated NameAnn SrcSpan
type Located = GenLocated () SrcSpan
-- For elements without annotations:
type instance Anno (RuleBndr (GhcPass p)) = ()
-- Or possibly
data NoAnn = NoAnn
type Located = GenLocated NoAnn SrcSpan
type instance Anno (RuleBndr (GhcPass p)) = NoAnn
Then we can get rid of the type SrcAnn ann = SrcSpanAnn' (EpAnn ann)
and type SrcSpanAnnA = SrcAnn AnnListItem
etc. types.
/cc @alanz @int-index @fendor