Simon Jakobi pushed to branch wip/sjakobi/T23414 at Glasgow Haskell Compiler / GHC

Commits:

12 changed files:

Changes:

  • compiler/GHC/Driver/Errors.hs
    ... ... @@ -15,6 +15,7 @@ import GHC.Utils.Json
    15 15
     import GHC.Utils.Error
    
    16 16
     import GHC.Utils.Outputable
    
    17 17
     import GHC.Utils.Logger
    
    18
    +import Data.List.NonEmpty (NonEmpty(..))
    
    18 19
     
    
    19 20
     reportError :: Logger -> NamePprCtx -> DiagOpts -> SrcSpan -> SDoc -> IO ()
    
    20 21
     reportError logger nameContext opts span doc = do
    
    ... ... @@ -47,7 +48,7 @@ printMessages logger msg_opts opts = mapM_ (printMessage logger msg_opts opts) .
    47 48
     printMessage :: forall a. (Diagnostic a) => Logger -> DiagnosticOpts a -> DiagOpts -> MsgEnvelope a -> IO ()
    
    48 49
     printMessage logger msg_opts opts message
    
    49 50
       | log_diags_as_json = do
    
    50
    -      decorated <- decorateDiagnostic logflags messageClass location doc
    
    51
    +      decorated <- decorateDiagnostic logflags messageClass location sourceSpans doc
    
    51 52
           let
    
    52 53
             rendered :: String
    
    53 54
             rendered = renderWithContext (log_default_user_context logflags) decorated
    
    ... ... @@ -57,7 +58,7 @@ printMessage logger msg_opts opts message
    57 58
     
    
    58 59
           logJsonMsg logger messageClass jsonMessage
    
    59 60
     
    
    60
    -  | otherwise = logMsg logger messageClass location doc
    
    61
    +  | otherwise = logMsg (pushLogHook renderWithSourceSpans logger) messageClass location doc
    
    61 62
       where
    
    62 63
         logflags :: LogFlags
    
    63 64
         logflags = logFlags logger
    
    ... ... @@ -80,9 +81,21 @@ printMessage logger msg_opts opts message
    80 81
         diagnostic :: a
    
    81 82
         diagnostic = errMsgDiagnostic message
    
    82 83
     
    
    84
    +    sourceSpans :: NonEmpty SrcSpan
    
    85
    +    sourceSpans = location :| diagnosticRelatedLocations diagnostic
    
    86
    +
    
    83 87
         severity :: Severity
    
    84 88
         severity = errMsgSeverity message
    
    85 89
     
    
    90
    +    renderWithSourceSpans :: LogAction -> LogAction
    
    91
    +    renderWithSourceSpans fallback logflags' msg_class' srcSpan' msg' =
    
    92
    +      case msg_class' of
    
    93
    +        MCDiagnostic _ _ _ -> do
    
    94
    +          decorated <- decorateDiagnostic logflags' msg_class' srcSpan' sourceSpans msg'
    
    95
    +          fallback logflags' MCInfo noSrcSpan decorated
    
    96
    +        _ ->
    
    97
    +          fallback logflags' msg_class' srcSpan' msg'
    
    98
    +
    
    86 99
         messageWithHints :: a -> SDoc
    
    87 100
         messageWithHints e =
    
    88 101
           let main_msg = formatBulleted $ diagnosticMessage msg_opts e
    

  • compiler/GHC/Driver/Errors/Ppr.hs
    ... ... @@ -87,6 +87,18 @@ instance Diagnostic GhcMessage where
    87 87
     
    
    88 88
       diagnosticCode = constructorCode @GHC
    
    89 89
     
    
    90
    +  diagnosticRelatedLocations = \case
    
    91
    +    GhcPsMessage m
    
    92
    +      -> diagnosticRelatedLocations m
    
    93
    +    GhcTcRnMessage m
    
    94
    +      -> diagnosticRelatedLocations m
    
    95
    +    GhcDsMessage m
    
    96
    +      -> diagnosticRelatedLocations m
    
    97
    +    GhcDriverMessage m
    
    98
    +      -> diagnosticRelatedLocations m
    
    99
    +    GhcUnknownMessage m
    
    100
    +      -> diagnosticRelatedLocations m
    
    101
    +
    
    90 102
     instance HasDefaultDiagnosticOpts DriverMessageOpts where
    
    91 103
       defaultOpts = DriverMessageOpts (defaultDiagnosticOpts @PsMessage) (defaultDiagnosticOpts @IfaceMessage)
    
    92 104
     
    

  • compiler/GHC/Rename/Utils.hs
    ... ... @@ -660,9 +660,10 @@ mkNameClashErr gre_env rdr_name gres = TcRnAmbiguousName gre_env rdr_name gres
    660 660
     
    
    661 661
     dupNamesErr :: NE.NonEmpty SrcSpan -> NE.NonEmpty RdrName -> RnM ()
    
    662 662
     dupNamesErr locs names
    
    663
    -  = addErrAt big_loc (TcRnBindingNameConflict (NE.head names) locs)
    
    663
    +  = addErrAt (NE.head sorted_locs)
    
    664
    +             (TcRnBindingNameConflict (NE.head names) sorted_locs)
    
    664 665
       where
    
    665
    -    big_loc = foldr1 combineSrcSpans locs
    
    666
    +    sorted_locs = NE.sortBy leftmost_smallest locs
    
    666 667
     
    
    667 668
     badQualBndrErr :: RdrName -> TcRnMessage
    
    668 669
     badQualBndrErr rdr_name = TcRnQualifiedBinder rdr_name
    

  • compiler/GHC/Tc/Errors/Ppr.hs
    ... ... @@ -3455,6 +3455,18 @@ instance Diagnostic TcRnMessage where
    3455 3455
     
    
    3456 3456
       diagnosticCode = constructorCode @GHC
    
    3457 3457
     
    
    3458
    +  diagnosticRelatedLocations = \case
    
    3459
    +    TcRnUnknownMessage m
    
    3460
    +      -> diagnosticRelatedLocations m
    
    3461
    +    TcRnMessageWithInfo _ (TcRnMessageDetailed _ msg')
    
    3462
    +      -> diagnosticRelatedLocations msg'
    
    3463
    +    TcRnWithHsDocContext _ msg'
    
    3464
    +      -> diagnosticRelatedLocations msg'
    
    3465
    +    TcRnBindingNameConflict _ locs
    
    3466
    +      -> NE.tail locs
    
    3467
    +    _ ->
    
    3468
    +      []
    
    3469
    +
    
    3458 3470
     pprTcRnBadlyLevelled :: LevelCheckReason -> Set.Set ThLevelIndex -> ThLevelIndex -> Maybe ErrorItem -> DecoratedSDoc
    
    3459 3471
     pprTcRnBadlyLevelled reason bind_lvls use_lvl lift_attempt = mkDecorated $
    
    3460 3472
              [ fsep [ text "Level error:", pprLevelCheckReason reason
    

  • compiler/GHC/Types/Error.hs
    ... ... @@ -66,6 +66,7 @@ module GHC.Types.Error
    66 66
        , mkLocMessageWarningGroups
    
    67 67
        , formatDiagnostic
    
    68 68
        , getCaretDiagnostic
    
    69
    +   , getCaretDiagnostics
    
    69 70
     
    
    70 71
        , jsonDiagnostic
    
    71 72
     
    
    ... ... @@ -108,8 +109,8 @@ import Data.Bifunctor
    108 109
     import Data.Foldable
    
    109 110
     import Data.List.NonEmpty ( NonEmpty (..) )
    
    110 111
     import qualified Data.List.NonEmpty as NE
    
    111
    -import Data.List ( intercalate )
    
    112
    -import Data.Maybe ( maybeToList )
    
    112
    +import Data.List ( intercalate, sort )
    
    113
    +import Data.Maybe ( mapMaybe, maybeToList )
    
    113 114
     import Data.Typeable ( Typeable )
    
    114 115
     import Numeric.Natural ( Natural )
    
    115 116
     import Text.Printf ( printf )
    
    ... ... @@ -277,6 +278,13 @@ class (Outputable (DiagnosticHint a), HasDefaultDiagnosticOpts (DiagnosticOpts a
    277 278
       -- #18516 tracks our progress toward this goal.
    
    278 279
       diagnosticCode    :: a -> Maybe DiagnosticCode
    
    279 280
     
    
    281
    +  -- | Additional locations related to this diagnostic.
    
    282
    +  --
    
    283
    +  -- When rendering caret diagnostics, these locations are shown alongside the
    
    284
    +  -- message's primary location.
    
    285
    +  diagnosticRelatedLocations :: a -> [SrcSpan]
    
    286
    +  diagnosticRelatedLocations _ = []
    
    287
    +
    
    280 288
     -- | An existential wrapper around an unknown diagnostic.
    
    281 289
     data UnknownDiagnostic opts hint where
    
    282 290
       UnknownDiagnostic :: (Diagnostic a, Typeable a)
    
    ... ... @@ -295,6 +303,7 @@ instance (HasDefaultDiagnosticOpts opts, Outputable hint) => Diagnostic (Unknown
    295 303
       diagnosticReason       (UnknownDiagnostic _ _ diag) = diagnosticReason diag
    
    296 304
       diagnosticHints        (UnknownDiagnostic _ f diag) = map f (diagnosticHints diag)
    
    297 305
       diagnosticCode         (UnknownDiagnostic _ _ diag) = diagnosticCode diag
    
    306
    +  diagnosticRelatedLocations (UnknownDiagnostic _ _ diag) = diagnosticRelatedLocations diag
    
    298 307
     
    
    299 308
     -- A fallback 'DiagnosticOpts' which can be used when there are no options
    
    300 309
     -- for a particular diagnostic.
    
    ... ... @@ -785,7 +794,25 @@ getSeverityColour severity = case severity of
    785 794
       SevIgnore -> const mempty
    
    786 795
     
    
    787 796
     getCaretDiagnostic :: MessageClass -> SrcSpan -> IO SDoc
    
    788
    -getCaretDiagnostic msg_class (RealSrcSpan span _) =
    
    797
    +getCaretDiagnostic msg_class span = getCaretDiagnostics msg_class (span :| [])
    
    798
    +
    
    799
    +getCaretDiagnostics :: MessageClass -> NonEmpty SrcSpan -> IO SDoc
    
    800
    +getCaretDiagnostics msg_class spans = do
    
    801
    +  let realSpans = dedupSortedRealSpans spans
    
    802
    +      maxMarginWidth =
    
    803
    +        foldl' (\acc s -> max acc (length (show (srcSpanStartLine s)))) 0 realSpans
    
    804
    +  vcat <$> traverse (getSingleCaretDiagnostic msg_class maxMarginWidth) realSpans
    
    805
    +  where
    
    806
    +    dedupSortedRealSpans :: NonEmpty SrcSpan -> [RealSrcSpan]
    
    807
    +    dedupSortedRealSpans = go Nothing . sort . mapMaybe srcSpanToRealSrcSpan . NE.toList
    
    808
    +      where
    
    809
    +        go _ [] = []
    
    810
    +        go prev (span:rest)
    
    811
    +          | Just span == prev = go prev rest
    
    812
    +          | otherwise         = span : go (Just span) rest
    
    813
    +
    
    814
    +getSingleCaretDiagnostic :: MessageClass -> Int -> RealSrcSpan -> IO SDoc
    
    815
    +getSingleCaretDiagnostic msg_class maxMarginWidth span =
    
    789 816
       caretDiagnostic <$> getSrcLine (srcSpanFile span) row
    
    790 817
       where
    
    791 818
         getSrcLine fn i =
    
    ... ... @@ -848,9 +875,9 @@ getCaretDiagnostic msg_class (RealSrcSpan span _) =
    848 875
                 | otherwise = srcSpanEndCol span - 1
    
    849 876
             width = max 1 (end - start)
    
    850 877
     
    
    851
    -        marginWidth = length rowStr
    
    878
    +        marginWidth = maxMarginWidth
    
    852 879
             marginSpace = replicate marginWidth ' ' ++ " |"
    
    853
    -        marginRow   = rowStr ++ " |"
    
    880
    +        marginRow   = replicate (marginWidth - length rowStr) ' ' ++ rowStr ++ " |"
    
    854 881
     
    
    855 882
             (srcLinePre,  srcLineRest) = splitAt start srcLine
    
    856 883
             (srcLineSpan, srcLinePost) = splitAt width srcLineRest
    
    ... ... @@ -858,7 +885,6 @@ getCaretDiagnostic msg_class (RealSrcSpan span _) =
    858 885
             caretEllipsis | multiline = "..."
    
    859 886
                           | otherwise = ""
    
    860 887
             caretLine = replicate start ' ' ++ replicate width '^' ++ caretEllipsis
    
    861
    -getCaretDiagnostic _ _ = pure empty
    
    862 888
     --
    
    863 889
     -- Queries
    
    864 890
     --
    

  • compiler/GHC/Utils/Logger.hs
    ... ... @@ -84,7 +84,7 @@ import GHC.Prelude
    84 84
     import GHC.Driver.Flags
    
    85 85
     import GHC.Types.Error
    
    86 86
       ( MessageClass (..), Severity (..)
    
    87
    -  , mkLocMessageWarningGroups,getCaretDiagnostic )
    
    87
    +  , mkLocMessageWarningGroups, getCaretDiagnostics )
    
    88 88
     -- import GHC.Types.Error ()
    
    89 89
     import GHC.Types.SrcLoc
    
    90 90
     
    
    ... ... @@ -102,6 +102,7 @@ import System.FilePath ( takeDirectory, (</>) )
    102 102
     import qualified Data.Map.Strict as Map
    
    103 103
     import Data.Map.Strict (Map)
    
    104 104
     import Data.List (stripPrefix)
    
    105
    +import Data.List.NonEmpty (NonEmpty(..))
    
    105 106
     import Data.Time
    
    106 107
     import System.IO
    
    107 108
     import Control.Monad
    
    ... ... @@ -423,7 +424,8 @@ defaultLogActionWithHandles out err logflags msg_class srcSpan msg
    423 424
           MCInfo                       -> printErrs msg
    
    424 425
           MCFatal                      -> printErrs msg
    
    425 426
           MCDiagnostic SevIgnore _ _   -> pure () -- suppress the message
    
    426
    -      MCDiagnostic _sev _rea _code -> decorateDiagnostic logflags msg_class srcSpan msg >>= printErrs
    
    427
    +      MCDiagnostic _sev _rea _code ->
    
    428
    +        decorateDiagnostic logflags msg_class srcSpan (srcSpan :| []) msg >>= printErrs
    
    427 429
         where
    
    428 430
           printOut   = defaultLogActionHPrintDoc  logflags False out
    
    429 431
           printErrs  = defaultLogActionHPrintDoc  logflags False err
    
    ... ... @@ -463,8 +465,8 @@ defaultLogActionWithHandles out err logflags msg_class srcSpan msg
    463 465
     --     `defaultLogActionWithHandles`)
    
    464 466
     --
    
    465 467
     -- This story is tracked by #24113.
    
    466
    -decorateDiagnostic :: LogFlags -> MessageClass -> SrcSpan -> SDoc -> IO SDoc
    
    467
    -decorateDiagnostic logflags msg_class srcSpan msg = addCaret
    
    468
    +decorateDiagnostic :: LogFlags -> MessageClass -> SrcSpan -> NonEmpty SrcSpan -> SDoc -> IO SDoc
    
    469
    +decorateDiagnostic logflags msg_class srcSpan sourceSpans msg = addCaret
    
    468 470
         where
    
    469 471
           -- Pretty print the warning flag, if any (#10752)
    
    470 472
           message :: SDoc
    
    ... ... @@ -474,7 +476,7 @@ decorateDiagnostic logflags msg_class srcSpan msg = addCaret
    474 476
           addCaret = do
    
    475 477
             caretDiagnostic <-
    
    476 478
                 if log_show_caret logflags
    
    477
    -            then getCaretDiagnostic msg_class srcSpan
    
    479
    +            then getCaretDiagnostics msg_class sourceSpans
    
    478 480
                 else pure empty
    
    479 481
             return $ getPprStyle $ \style ->
    
    480 482
               withPprStyle (setStyleColoured True style)
    

  • testsuite/tests/patsyn/should_fail/T14114.stderr
    1
    -
    
    2 1
     T14114.hs:4:20: error: [GHC-10498]
    
    3 2
         • Conflicting definitions for ‘a’
    
    4 3
           Bound at: T14114.hs:4:20
    
    5 4
                     T14114.hs:4:22
    
    6 5
         • In a pattern synonym declaration
    
    6
    +  |
    
    7
    +4 | pattern Foo1 a <- (a,a)
    
    8
    +  |                    ^
    
    9
    +  |
    
    10
    +4 | pattern Foo1 a <- (a,a)
    
    11
    +  |                      ^
    
    7 12
     
    
    8 13
     T14114.hs:5:20: error: [GHC-10498]
    
    9 14
         • Conflicting definitions for ‘a’
    
    10 15
           Bound at: T14114.hs:5:20
    
    11 16
                     T14114.hs:5:22
    
    12 17
         • In a pattern synonym declaration
    
    18
    +  |
    
    19
    +5 | pattern Foo2 a  = (a,a)
    
    20
    +  |                    ^
    
    21
    +  |
    
    22
    +5 | pattern Foo2 a  = (a,a)
    
    23
    +  |                      ^
    
    13 24
     
    
    14 25
     T14114.hs:6:20: error: [GHC-10498]
    
    15 26
         • Conflicting definitions for ‘a’
    
    16 27
           Bound at: T14114.hs:6:20
    
    17 28
                     T14114.hs:6:22
    
    18 29
         • In a pattern synonym declaration
    
    30
    +  |
    
    31
    +6 | pattern Foo3 a <- (a,a) where
    
    32
    +  |                    ^
    
    33
    +  |
    
    34
    +6 | pattern Foo3 a <- (a,a) where
    
    35
    +  |                      ^
    
    36
    +

  • testsuite/tests/patsyn/should_fail/all.T
    ... ... @@ -40,7 +40,7 @@ test('T26465', normal, compile_fail, [''])
    40 40
     test('T13349', normal, compile_fail, [''])
    
    41 41
     test('T13470', normal, compile_fail, [''])
    
    42 42
     test('T14112', normal, compile_fail, [''])
    
    43
    -test('T14114', normal, compile_fail, [''])
    
    43
    +test('T14114', normal, compile_fail, ['-fdiagnostics-show-caret'])
    
    44 44
     test('T14507', normal, compile_fail, ['-dsuppress-uniques'])
    
    45 45
     test('T15289', normal, compile_fail, [''])
    
    46 46
     test('T15685', normal, compile_fail, [''])
    

  • testsuite/tests/rename/should_fail/all.T
    1 1
     test('rnfail001', normal, compile_fail, [''])
    
    2 2
     test('rnfail002', normal, compile_fail, [''])
    
    3 3
     test('rnfail003', normal, compile_fail, [''])
    
    4
    -test('rnfail004', normal, compile_fail, [''])
    
    4
    +test('rnfail004', normal, compile_fail, ['-fdiagnostics-show-caret'])
    
    5 5
     test('rnfail007', normal, compile_fail, [''])
    
    6 6
     test('rnfail008', normal, compile_fail, [''])
    
    7 7
     test('rnfail009', normal, compile_fail, [''])
    

  • testsuite/tests/rename/should_fail/rnfail004.stderr
    1
    -
    
    2
    -rnfail004.hs:6:5: [GHC-10498]
    
    1
    +rnfail004.hs:6:5: error: [GHC-10498]
    
    3 2
         Conflicting definitions for ‘a’
    
    4 3
         Bound at: rnfail004.hs:6:5
    
    5 4
                   rnfail004.hs:7:10
    
    5
    +  |
    
    6
    +6 |     a           = []
    
    7
    +  |     ^
    
    8
    +  |
    
    9
    +7 |     (b,c,a)     = ([],[],d)
    
    10
    +  |          ^
    
    6 11
     
    
    7
    -rnfail004.hs:7:6: [GHC-10498]
    
    12
    +rnfail004.hs:7:6: error: [GHC-10498]
    
    8 13
         Conflicting definitions for ‘b’
    
    9 14
         Bound at: rnfail004.hs:7:6
    
    10 15
                   rnfail004.hs:8:8
    
    16
    +  |
    
    17
    +7 |     (b,c,a)     = ([],[],d)
    
    18
    +  |      ^
    
    19
    +  |
    
    20
    +8 |     [d,b,_]     = ([],a,[])
    
    21
    +  |        ^
    
    22
    +

  • testsuite/tests/typecheck/should_fail/all.T
    ... ... @@ -31,7 +31,7 @@ test('tcfail034', normal, compile_fail, [''])
    31 31
     test('tcfail035', normal, compile_fail, [''])
    
    32 32
     test('tcfail036', normal, compile_fail, [''])
    
    33 33
     test('tcfail037', normal, compile_fail, [''])
    
    34
    -test('tcfail038', normal, compile_fail, [''])
    
    34
    +test('tcfail038', normal, compile_fail, ['-fdiagnostics-show-caret'])
    
    35 35
     test('tcfail040', normal, compile_fail, [''])
    
    36 36
     test('tcfail041', normal, compile_fail, [''])
    
    37 37
     test('tcfail042', normal, compile_fail, [''])
    

  • testsuite/tests/typecheck/should_fail/tcfail038.stderr
    1
    -
    
    2
    -tcfail038.hs:7:11: [GHC-10498]
    
    1
    +tcfail038.hs:7:11: error: [GHC-10498]
    
    3 2
         Conflicting definitions for ‘==’
    
    4 3
         Bound at: tcfail038.hs:7:11-12
    
    5 4
                   tcfail038.hs:9:11-12
    
    5
    +  |
    
    6
    +7 |         a == b = True
    
    7
    +  |           ^^
    
    8
    +  |
    
    9
    +9 |         a == b = False
    
    10
    +  |           ^^
    
    6 11
     
    
    7
    -tcfail038.hs:8:11: [GHC-10498]
    
    12
    +tcfail038.hs:8:11: error: [GHC-10498]
    
    8 13
         Conflicting definitions for ‘/=’
    
    9 14
         Bound at: tcfail038.hs:8:11-12
    
    10 15
                   tcfail038.hs:10:11-12
    
    16
    +   |
    
    17
    + 8 |         a /= b = False
    
    18
    +   |           ^^
    
    19
    +   |
    
    20
    +10 |         a /= b = True
    
    21
    +   |           ^^
    
    22
    +