Inconsistent SrcSpan treatment in TH splices
(Spun off from a discussion in !7574 (comment 417656).)
If you compile this program with -ddump-rn-ast enabled:
{-# LANGUAGE TemplateHaskell #-}
module Bug where
f = $([| True |])
You will see:
==================== Renamer ====================
(Just
((,,,)
(HsGroup
(NoExtField)
(XValBindsLR
(NValBinds
[((,)
(NonRecursive)
{Bag(LocatedA (HsBind Name)):
[(L
(SrcSpanAnn (EpAnn
(Anchor
{ Bug.hs:4:1-17 }
(UnchangedAnchor))
(AnnListItem
[])
(EpaComments
[])) { Bug.hs:4:1-17 })
(FunBind
{NameSet:
[]}
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:1 })
{Name: Bug.f})
(MG
(NoExtField)
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:1-17 })
[(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:1-17 })
(Match
(EpAnnNotUsed)
(FunRhs
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:1 })
{Name: Bug.f})
(Prefix)
(NoSrcStrict))
[]
(GRHSs
(EpaComments
[])
[(L
(SrcSpanAnn
(EpAnnNotUsed)
{ Bug.hs:4:3-17 })
(GRHS
(EpAnnNotUsed)
[]
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:5-17 })
(HsPar
(EpAnnNotUsed)
(L
(NoTokenLoc)
(HsTok))
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:6-17 })
(HsSpliceE
(EpAnnNotUsed)
(HsSpliced
(NoExtField)
(ThModFinalizers)
(HsSplicedExpr
(HsVar
(NoExtField)
(L
(SrcSpanAnn (EpAnnNotUsed) { <no location info> })
{Name: GHC.Types.True}))))))
(L
(NoTokenLoc)
(HsTok))))))]
(EmptyLocalBinds
(NoExtField)))))])
(FromSource))
[]))]})]
[]))
[]
[]
[]
[]
[]
[]
[]
[]
[]
[])
[(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:2:8-10 })
(ImportDecl
(NoExtField)
(NoSourceText)
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:2:8-10 })
{ModuleName: Prelude})
(NoPkgQual)
(NotBoot)
(False)
(NotQualified)
(True)
(Nothing)
(Nothing)))]
(Nothing)
(Nothing)))
The peculiar part is here:
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:6-17 })
(HsSpliceE
(EpAnnNotUsed)
(HsSpliced
(NoExtField)
(ThModFinalizers)
(HsSplicedExpr
(HsVar
(NoExtField)
(L
(SrcSpanAnn (EpAnnNotUsed) { <no location info> })
{Name: GHC.Types.True}))))))
This part corresponds to the spliced-in True expression. Note that the outermost SrcSpan has a source location of Bug.hs:4:6-17, as expected. The inner SrcSpan corresponding to the True bit, however, has <no location info>.
On its own, this might seem like a reasonable choice. After all, spliced-in expressions don't really have SrcSpans corresponding to the module in which they were spliced, so it would be a perfectly valid choice to just use <no location info> for all spliced-in subexpressions. However, this is not the choice that GHC makes! Let's change the program slightly:
f = $([| True :: Bool |])
This has the following -ddump-rn-ast output:
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:6-25 })
(HsSpliceE
(EpAnnNotUsed)
(HsSpliced
(NoExtField)
(ThModFinalizers)
(HsSplicedExpr
(ExprWithTySig
(NoExtField)
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:6-25 })
(HsVar
(NoExtField)
(L
(SrcSpanAnn (EpAnnNotUsed) { <no location info> })
{Name: GHC.Types.True})))
(HsWC
[]
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:6-25 })
(HsSig
(NoExtField)
(HsOuterImplicit
[])
(L
(SrcSpanAnn (EpAnnNotUsed) { Bug.hs:4:6-25 })
(HsTyVar
(EpAnnNotUsed)
(NotPromoted)
(L
(SrcSpanAnn (EpAnnNotUsed) { <no location info> })
{Name: GHC.Types.Bool})))))))))))
Notice that some parts of the HsSpliceE, such as the True and Bool parts, have <no location info>. On the other hand, other parts like the HsWC, HsSig, and HsTyVar do have SrcSpans, which are copied from the Bug.hs:4:6-25 used on the outermost HsSpliceE.
This is oddly inconsistent. TH splicing should consistently apply the same approach to source locations everywhere instead of whatever it is doing currently. Since TH is already threading around SrcSpans to use in some places, I propose that it simply use the same SrcSpans everywhere. This includes the True and Bool parts seen above.