Remove Ord SrcLoc, Ord SrcSpan
Before this patch, GHC relied on Ord SrcSpan
to identify source elements, by using SrcSpan
as Map
keys:
blackList :: Map SrcSpan () -- compiler/GHC/HsToCore/Coverage.hs
instanceMap :: Map SrcSpan Name -- compiler/GHC/HsToCore/Docs.hs
Firstly, this design is not valid in presence of UnhelpfulSpan
, as it
distinguishes between UnhelpfulSpan "X"
and UnhelpfulSpan "Y"
, but those
strings are messages for the user, unfit to serve as identifiers for source
elements.
Secondly, this design made it hard to extend SrcSpan
with additional data.
Recall that the definition of SrcSpan
is:
data SrcSpan =
RealSrcSpan !RealSrcSpan
| UnhelpfulSpan !FastString
Say we want to extend the RealSrcSpan
constructor with additional information:
data SrcSpan =
RealSrcSpan !RealSrcSpan !AdditionalInformation
| UnhelpfulSpan !FastString
getAdditionalInformation :: SrcSpan -> AdditionalInformation
getAdditionalInformation (RealSrcSpan _ a) = a
Now, in order for Map SrcSpan
to keep working correctly, we must ignore additional
information when comparing SrcSpan
values:
instance Ord SrcSpan where
compare (RealSrcSpan r1 _) (RealSrcSpan r2 _) = compare r1 r2
...
However, this would violate an important law:
-
a == b
thereforef a == f b
Ignoring AdditionalInformation
in comparisons would mean that with
f=getAdditionalInformation
, the law above does not hold.
A more robust design is to avoid Ord SrcSpan
altogether, which is what this patch implements.
The mappings are changed to use RealSrcSpan
instead:
blackList :: Set RealSrcSpan -- compiler/GHC/HsToCore/Coverage.hs
instanceMap :: Map RealSrcSpan Name -- compiler/GHC/HsToCore/Docs.hs
All SrcSpan
comparisons are now done with explicit comparison strategies:
SrcLoc.leftmost_smallest
SrcLoc.leftmost_largest
SrcLoc.rightmost_smallest
These strategies are not subject to the law mentioned above and can easily
discard both the string stored in UnhelpfulSpan
and AdditionalInformation
.