Skip to content

Empty Haddock comments no longer occur in the AST as `HsDoc`

Summary

Consider the following two type signatures.

foo :: {- |-} A -> B
bar :: {- | -} A -> B

Comparing the AST (with -haddock) of foo and bar, note that foo does not contain a HsDoc (searchf or WithHsDocIdentifiers), but bar does:

foo

bar

(L
 (SrcSpanAnn (EpAnn
              (Anchor
               { <interactive>:1:1-20 }
               (UnchangedAnchor))
              (AnnListItem
               [])
              (EpaComments
               [])) { <interactive>:1:1-20 })
 (SigD
  (NoExtField)
  (TypeSig
   (EpAnn
    (Anchor
     { <interactive>:1:1-3 }
     (UnchangedAnchor))
    (AnnSig
     (AddEpAnn AnnDcolon (EpaSpan { <interactive>:1:5-6 }))
     [])
    (EpaComments
     []))
   [(L
     (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:1-3 })
     (Unqual
      {OccName: foo}))]
   (HsWC
    (NoExtField)
    (L
     (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:15-20 })
     (HsSig
      (NoExtField)
      (HsOuterImplicit
       (NoExtField))
      (L
       (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:15-20 })
       (HsFunTy
        (EpAnn
         (Anchor
          { <interactive>:1:15 }
          (UnchangedAnchor))
         (NoEpAnns)
         (EpaComments
          []))
        (HsUnrestrictedArrow
         (L
          (TokenLoc
           (EpaSpan { <interactive>:1:17-18 }))
          (HsNormalTok)))
        (L
         (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:15 })
         (HsTyVar
          (EpAnn
           (Anchor
            { <interactive>:1:15 }
            (UnchangedAnchor))
           []
           (EpaComments
            []))
          (NotPromoted)
          (L
           (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:15 })
           (Unqual
            {OccName: A}))))
        (L
         (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:20 })
         (HsTyVar
          (EpAnn
           (Anchor
            { <interactive>:1:20 }
            (UnchangedAnchor))
           []
           (EpaComments
            []))
          (NotPromoted)
          (L
           (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:20 })
           (Unqual
            {OccName: B}))))))))))))
(L
 (SrcSpanAnn (EpAnn
              (Anchor
               { <interactive>:1:1-21 }
               (UnchangedAnchor))
              (AnnListItem
               [])
              (EpaComments
               [])) { <interactive>:1:1-21 })
 (SigD
  (NoExtField)
  (TypeSig
   (EpAnn
    (Anchor
     { <interactive>:1:1-3 }
     (UnchangedAnchor))
    (AnnSig
     (AddEpAnn AnnDcolon (EpaSpan { <interactive>:1:5-6 }))
     [])
    (EpaComments
     []))
   [(L
     (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:1-3 })
     (Unqual
      {OccName: bar}))]
   (HsWC
    (NoExtField)
    (L
     (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:16-21 })
     (HsSig
      (NoExtField)
      (HsOuterImplicit
       (NoExtField))
      (L
       (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:16-21 })
       (HsFunTy
        (EpAnn
         (Anchor
          { <interactive>:1:16 }
          (UnchangedAnchor))
         (NoEpAnns)
         (EpaComments
          []))
        (HsUnrestrictedArrow
         (L
          (TokenLoc
           (EpaSpan { <interactive>:1:18-19 }))
          (HsNormalTok)))
        (L
         (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:16 })
         (HsDocTy
          (EpAnnNotUsed)
          (L
           (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:16 })
           (HsTyVar
            (EpAnn
             (Anchor
              { <interactive>:1:16 }
              (UnchangedAnchor))
             []
             (EpaComments
              []))
            (NotPromoted)
            (L
             (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:16 })
             (Unqual
              {OccName: A}))))
          (L
           { <interactive>:1:8-14 }
           (WithHsDocIdentifiers
            (NestedDocString
             (HsDocStringNext)
             (L
              { <interactive>:1:8-14 }
              (HsDocStringChunk
               " ")))
            []))))
        (L
         (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:21 })
         (HsTyVar
          (EpAnn
           (Anchor
            { <interactive>:1:21 }
            (UnchangedAnchor))
           []
           (EpaComments
            []))
          (NotPromoted)
          (L
           (SrcSpanAnn (EpAnnNotUsed) { <interactive>:1:21 })
           (Unqual
            {OccName: B}))))))))))))

Is there a particular reason for this? In GHC 8.10, the AST contained Haddock comments in both cases.

Concrete effects of this behavior:

  • It makes the job of formatters like Ormolu (see issues 1068, 1065, 726) that check of AST discrepancies automatically harder than necessary, as eg a natural rewrite from
    foo ::
      -- |
      --
      A ->
      B
    to
    foo ::
      -- |
      A -> 
      B
    contains a Haddock comment in the AST in the first snippet, but not in the second.
  • A nice Haddock trick by @tomjaguarpaw1 (blog post, search for "Forced type signatures to wrap") does no longer work.

Ideally, the behavior would be changed as it was in 8.10; I could try to do that in case this behavior is not intentional.

Environment

  • GHC version used: Any GHC since 9.0 (I think this change is due to !2377 (closed))
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information