summaryrefslogtreecommitdiff
path: root/compiler/GHC/Parser/Annotation.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Parser/Annotation.hs')
-rw-r--r--compiler/GHC/Parser/Annotation.hs36
1 files changed, 31 insertions, 5 deletions
diff --git a/compiler/GHC/Parser/Annotation.hs b/compiler/GHC/Parser/Annotation.hs
index 1692d394b5..9555291530 100644
--- a/compiler/GHC/Parser/Annotation.hs
+++ b/compiler/GHC/Parser/Annotation.hs
@@ -100,7 +100,7 @@ import qualified GHC.Data.Strict as Strict
{-
Note [exact print annotations]
-~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Given a parse tree of a Haskell module, how can we reconstruct
the original Haskell source code, retaining all whitespace and
source code comments? We need to track the locations of all
@@ -394,7 +394,7 @@ instance Outputable EpaComment where
-- The usual way an 'AddEpAnn' is created is using the 'mj' ("make
-- jump") function, and then it can be inserted into the appropriate
-- annotation.
-data AddEpAnn = AddEpAnn AnnKeywordId EpaLocation deriving (Data,Eq,Ord)
+data AddEpAnn = AddEpAnn AnnKeywordId EpaLocation deriving (Data,Eq)
-- | The anchor for an @'AnnKeywordId'@. The Parser inserts the
-- @'EpaSpan'@ variant, giving the exact location of the original item
@@ -460,6 +460,9 @@ instance Outputable EpaLocation where
instance Outputable AddEpAnn where
ppr (AddEpAnn kw ss) = text "AddEpAnn" <+> ppr kw <+> ppr ss
+instance Ord AddEpAnn where
+ compare (AddEpAnn kw1 loc1) (AddEpAnn kw2 loc2) = compare (loc1, kw1) (loc2,kw2)
+
-- ---------------------------------------------------------------------
-- | The exact print annotations (EPAs) are kept in the HsSyn AST for
@@ -802,7 +805,8 @@ addTrailingAnnToL s t cs EpAnnNotUsed
addTrailingAnnToL _ t cs n = n { anns = addTrailing (anns n)
, comments = comments n <> cs }
where
- addTrailing n = n { al_trailing = t : al_trailing n }
+ -- See Note [list append in addTrailing*]
+ addTrailing n = n { al_trailing = al_trailing n ++ [t]}
-- | Helper function used in the parser to add a 'TrailingAnn' items
-- to an existing annotation.
@@ -813,7 +817,8 @@ addTrailingAnnToA s t cs EpAnnNotUsed
addTrailingAnnToA _ t cs n = n { anns = addTrailing (anns n)
, comments = comments n <> cs }
where
- addTrailing n = n { lann_trailing = t : lann_trailing n }
+ -- See Note [list append in addTrailing*]
+ addTrailing n = n { lann_trailing = lann_trailing n ++ [t] }
-- | Helper function used in the parser to add a comma location to an
-- existing annotation.
@@ -822,8 +827,29 @@ addTrailingCommaToN s EpAnnNotUsed l
= EpAnn (spanAsAnchor s) (NameAnnTrailing [AddCommaAnn l]) emptyComments
addTrailingCommaToN _ n l = n { anns = addTrailing (anns n) l }
where
+ -- See Note [list append in addTrailing*]
addTrailing :: NameAnn -> EpaLocation -> NameAnn
- addTrailing n l = n { nann_trailing = AddCommaAnn l : nann_trailing n }
+ addTrailing n l = n { nann_trailing = nann_trailing n ++ [AddCommaAnn l]}
+
+{-
+Note [list append in addTrailing*]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The addTrailingAnnToL, addTrailingAnnToA and addTrailingCommaToN
+functions are used to add a separator for an item when it occurs in a
+list. So they are used to capture a comma, vbar, semicolon and similar.
+
+In general, a given element will have zero or one of these. In
+extreme (test) cases, there may be multiple semicolons.
+
+In exact printing we sometimes convert the EpaLocation variant for an
+trailing annotation to the EpaDelta variant, which cannot be sorted.
+
+Hence it is critical that these annotations are captured in the order
+they appear in the original source file.
+
+And so we use the less efficient list append to preserve the order,
+knowing that in most cases the original list is empty.
+-}
-- ---------------------------------------------------------------------