Simon Hengel pushed to branch wip/sol/interactive-error-hints at Glasgow Haskell Compiler / GHC
Commits:
-
4454366a
by Simon Hengel at 2026-06-22T23:59:01+07:00
12 changed files:
- + changelog.d/interactive-error-hints
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Utils/Outputable.hs
- docs/users_guide/ghci.rst
- ghc/GHCi/UI/Exception.hs
- ghc/Main.hs
- testsuite/tests/ghci/prog-mhu002/prog-mhu002c.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout-mingw32
Changes:
| 1 | +section: compiler
|
|
| 2 | +synopsis:
|
|
| 3 | + Add flags `-finteractive-error-hints` / `-fno-interactive-error-hints` that
|
|
| 4 | + control whether GHCi specific error hints are printed.
|
|
| 5 | +issues: #27409
|
|
| 6 | +mrs: !16225 |
| ... | ... | @@ -1570,6 +1570,7 @@ initSDocContext dflags style = SDC |
| 1570 | 1570 | , sdocLineLength = pprCols dflags
|
| 1571 | 1571 | , sdocCanUseUnicode = useUnicode dflags
|
| 1572 | 1572 | , sdocPrintErrIndexLinks = overrideWith (canUseErrorLinks dflags) (useErrorLinks dflags)
|
| 1573 | + , sdocInteractiveErrorHints = gopt Opt_InteractiveErrorHints dflags
|
|
| 1573 | 1574 | , sdocHexWordLiterals = gopt Opt_HexWordLiterals dflags
|
| 1574 | 1575 | , sdocPprDebug = dopt Opt_D_ppr_debug dflags
|
| 1575 | 1576 | , sdocPrintUnicodeSyntax = gopt Opt_PrintUnicodeSyntax dflags
|
| ... | ... | @@ -861,6 +861,7 @@ data GeneralFlag |
| 861 | 861 | |
| 862 | 862 | -- Error message suppression
|
| 863 | 863 | | Opt_ShowErrorContext
|
| 864 | + | Opt_InteractiveErrorHints
|
|
| 864 | 865 | |
| 865 | 866 | -- Object code determinism
|
| 866 | 867 | | Opt_ObjectDeterminism
|
| ... | ... | @@ -2665,6 +2665,7 @@ fFlagsDeps = [ |
| 2665 | 2665 | (addWarn "-compact-unwind is only implemented by the darwin platform. Ignoring.")
|
| 2666 | 2666 | return dflags)),
|
| 2667 | 2667 | flagSpec "show-error-context" Opt_ShowErrorContext,
|
| 2668 | + flagSpec "interactive-error-hints" Opt_InteractiveErrorHints,
|
|
| 2668 | 2669 | flagSpec "cmm-thread-sanitizer" Opt_CmmThreadSanitizer,
|
| 2669 | 2670 | flagSpec "split-sections" Opt_SplitSections,
|
| 2670 | 2671 | flagSpec "break-points" Opt_InsertBreakpoints,
|
| ... | ... | @@ -43,19 +43,44 @@ instance Outputable GhcHint where |
| 43 | 43 | -> case extHint of
|
| 44 | 44 | SuggestSingleExtension extraUserInfo ext ->
|
| 45 | 45 | ("Perhaps you intended to use" <+> extension_with_implied ext)
|
| 46 | - $$ extraUserInfo
|
|
| 46 | + $$ interactiveErrorHints [ext] extraUserInfo False
|
|
| 47 | 47 | SuggestAnyExtension extraUserInfo exts ->
|
| 48 | 48 | (enable "any" <+> unquotedListWith "or" (map implied exts))
|
| 49 | - $$ extraUserInfo
|
|
| 49 | + $$ interactiveErrorHints exts extraUserInfo True
|
|
| 50 | 50 | SuggestExtensions extraUserInfo exts ->
|
| 51 | 51 | (enable "all" <+> unquotedListWith "and" (map implied exts))
|
| 52 | - $$ extraUserInfo
|
|
| 52 | + $$ interactiveErrorHints exts extraUserInfo False
|
|
| 53 | 53 | SuggestExtensionInOrderTo extraUserInfo ext ->
|
| 54 | 54 | ("Use" <+> extension_with_implied ext)
|
| 55 | - $$ extraUserInfo
|
|
| 55 | + $$ interactiveErrorHints [ext] extraUserInfo False
|
|
| 56 | 56 | where extension_with_implied ext = "the" <+> quotes (ppr ext) <+> "extension" <+> pprImpliedExtensions ext
|
| 57 | 57 | implied ext = quotes (ppr ext) <+> pprImpliedExtensions ext
|
| 58 | 58 | enable any_or_all = "Enable" <+> any_or_all <+> "of the following extensions" <> colon
|
| 59 | + |
|
| 60 | + interactiveErrorHints :: [LangExt.Extension] -> SDoc -> Bool -> SDoc
|
|
| 61 | + interactiveErrorHints exts doc enable_any = sdocOption sdocInteractiveErrorHints $ \ case
|
|
| 62 | + True -> suggestSetExt exts doc enable_any
|
|
| 63 | + False -> doc
|
|
| 64 | + |
|
| 65 | + -- Suggest enabling extension with :set -X<ext>
|
|
| 66 | + -- SuggestAnyExtension will be on multiple lines so the user can select which to enable without editing
|
|
| 67 | + suggestSetExt :: [LangExt.Extension] -> SDoc -> Bool -> SDoc
|
|
| 68 | + suggestSetExt exts doc enable_any = doc $$ hang header 2 exts_cmds
|
|
| 69 | + where
|
|
| 70 | + header = text "You may enable" <+> which <+> text "language extension" <> plural exts <+> text "in GHCi with:"
|
|
| 71 | + which
|
|
| 72 | + | [ _ext ] <- exts
|
|
| 73 | + = text "this"
|
|
| 74 | + | otherwise
|
|
| 75 | + = if enable_any
|
|
| 76 | + then text "these"
|
|
| 77 | + else text "all of these"
|
|
| 78 | + exts_cmds
|
|
| 79 | + | enable_any
|
|
| 80 | + = vcat $ map (\ext -> text ":set -X" <> ppr ext) exts
|
|
| 81 | + | otherwise
|
|
| 82 | + = text ":set" <> hcat (map (\ext -> text " -X" <> ppr ext) exts)
|
|
| 83 | + |
|
| 59 | 84 | SuggestCorrectPragmaName suggestions
|
| 60 | 85 | -> text "Perhaps you meant" <+> quotedListWithOr (map text suggestions)
|
| 61 | 86 | SuggestMissingDo
|
| ... | ... | @@ -398,6 +398,7 @@ data SDocContext = SDC |
| 398 | 398 | -- ^ True if Unicode encoding is supported
|
| 399 | 399 | -- and not disabled by GHC_NO_UNICODE environment variable
|
| 400 | 400 | , sdocPrintErrIndexLinks :: !Bool
|
| 401 | + , sdocInteractiveErrorHints :: !Bool
|
|
| 401 | 402 | , sdocHexWordLiterals :: !Bool
|
| 402 | 403 | , sdocPprDebug :: !Bool
|
| 403 | 404 | , sdocPrintUnicodeSyntax :: !Bool
|
| ... | ... | @@ -466,6 +467,7 @@ defaultSDocContext = SDC |
| 466 | 467 | , sdocLineLength = defaultSDocCols
|
| 467 | 468 | , sdocCanUseUnicode = False
|
| 468 | 469 | , sdocPrintErrIndexLinks = False
|
| 470 | + , sdocInteractiveErrorHints = False
|
|
| 469 | 471 | , sdocHexWordLiterals = False
|
| 470 | 472 | , sdocPprDebug = False
|
| 471 | 473 | , sdocPrintUnicodeSyntax = False
|
| ... | ... | @@ -2114,6 +2114,27 @@ mostly obvious. |
| 2114 | 2114 | If disabled, only the target given last on the command line interface will be
|
| 2115 | 2115 | added to interactive context of the GHCi session.
|
| 2116 | 2116 | |
| 2117 | +.. ghc-flag:: -finteractive-error-hints
|
|
| 2118 | + :shortdesc: Print GHCi specific error hints.
|
|
| 2119 | + :type: dynamic
|
|
| 2120 | + :reverse: -fno-interactive-error-hints
|
|
| 2121 | + :category:
|
|
| 2122 | + |
|
| 2123 | + :default: on
|
|
| 2124 | + :since: XXX
|
|
| 2125 | + |
|
| 2126 | + By default, GHCi extends error hints with GHCi specific instructions.
|
|
| 2127 | + |
|
| 2128 | + Example:
|
|
| 2129 | + |
|
| 2130 | + .. code-block:: none
|
|
| 2131 | + |
|
| 2132 | + Perhaps you intended to use the ‘BlockArguments’ extension
|
|
| 2133 | + You may enable this language extension in GHCi with:
|
|
| 2134 | + :set -XBlockArguments
|
|
| 2135 | + |
|
| 2136 | + This can be disabled with `-fno-interactive-error-hints`.
|
|
| 2137 | + |
|
| 2117 | 2138 | Packages
|
| 2118 | 2139 | ~~~~~~~~
|
| 2119 | 2140 |
| ... | ... | @@ -23,8 +23,6 @@ import GHC.Driver.Errors.Types |
| 23 | 23 | import GHC.Iface.Errors.Ppr
|
| 24 | 24 | import GHC.Iface.Errors.Types
|
| 25 | 25 | |
| 26 | -import qualified GHC.LanguageExtensions as LangExt
|
|
| 27 | - |
|
| 28 | 26 | import GHC.Tc.Errors.Ppr
|
| 29 | 27 | import GHC.Tc.Errors.Types
|
| 30 | 28 | |
| ... | ... | @@ -137,7 +135,7 @@ instance Diagnostic GhciMessage where |
| 137 | 135 | GhciUnknownMessage m -> diagnosticReason m
|
| 138 | 136 | |
| 139 | 137 | diagnosticHints = \case
|
| 140 | - GhciGhcMessage m -> map GhciGhcHint (ghciDiagnosticHints m)
|
|
| 138 | + GhciGhcMessage m -> map GhciGhcHint (diagnosticHints m)
|
|
| 141 | 139 | GhciCommandMessage m -> map GhciCommandHint (diagnosticHints m)
|
| 142 | 140 | GhciUnknownMessage m -> diagnosticHints m
|
| 143 | 141 | |
| ... | ... | @@ -146,40 +144,6 @@ instance Diagnostic GhciMessage where |
| 146 | 144 | GhciCommandMessage m -> diagnosticCode m
|
| 147 | 145 | GhciUnknownMessage m -> diagnosticCode m
|
| 148 | 146 | |
| 149 | - |
|
| 150 | --- | Modifications to hint messages which we want to display in GHCi.
|
|
| 151 | -ghciDiagnosticHints :: GhcMessage -> [GhcHint]
|
|
| 152 | -ghciDiagnosticHints msg = map modifyHintForGHCi (diagnosticHints msg)
|
|
| 153 | - where
|
|
| 154 | - modifyHintForGHCi :: GhcHint -> GhcHint
|
|
| 155 | - modifyHintForGHCi = \case
|
|
| 156 | - SuggestExtension extHint -> SuggestExtension $ modifyExtHintForGHCi extHint
|
|
| 157 | - hint -> hint
|
|
| 158 | - modifyExtHintForGHCi :: LanguageExtensionHint -> LanguageExtensionHint
|
|
| 159 | - modifyExtHintForGHCi = \case
|
|
| 160 | - SuggestSingleExtension doc ext -> SuggestSingleExtension (suggestSetExt [ext] doc False) ext
|
|
| 161 | - SuggestExtensionInOrderTo doc ext -> SuggestExtensionInOrderTo (suggestSetExt [ext] doc False) ext
|
|
| 162 | - SuggestAnyExtension doc exts -> SuggestAnyExtension (suggestSetExt exts doc True ) exts
|
|
| 163 | - SuggestExtensions doc exts -> SuggestExtensions (suggestSetExt exts doc False) exts
|
|
| 164 | - -- Suggest enabling extension with :set -X<ext>
|
|
| 165 | - -- SuggestAnyExtension will be on multiple lines so the user can select which to enable without editing
|
|
| 166 | - suggestSetExt :: [LangExt.Extension] -> SDoc -> Bool -> SDoc
|
|
| 167 | - suggestSetExt exts doc enable_any = doc $$ hang header 2 exts_cmds
|
|
| 168 | - where
|
|
| 169 | - header = text "You may enable" <+> which <+> text "language extension" <> plural exts <+> text "in GHCi with:"
|
|
| 170 | - which
|
|
| 171 | - | [ _ext ] <- exts
|
|
| 172 | - = text "this"
|
|
| 173 | - | otherwise
|
|
| 174 | - = if enable_any
|
|
| 175 | - then text "these"
|
|
| 176 | - else text "all of these"
|
|
| 177 | - exts_cmds
|
|
| 178 | - | enable_any
|
|
| 179 | - = vcat $ map (\ext -> text ":set -X" <> ppr ext) exts
|
|
| 180 | - | otherwise
|
|
| 181 | - = text ":set" <> hcat (map (\ext -> text " -X" <> ppr ext) exts)
|
|
| 182 | - |
|
| 183 | 147 | -- | Modifications to error messages which we want to display in GHCi
|
| 184 | 148 | ghciDiagnosticMessage :: GhcMessageOpts -> GhcMessage -> DecoratedSDoc
|
| 185 | 149 | ghciDiagnosticMessage ghc_opts msg =
|
| ... | ... | @@ -199,6 +199,7 @@ main' postLoadMode units dflags0 args flagWarnings = do |
| 199 | 199 | | DoRun <- postLoadMode = def_ghci_flags
|
| 200 | 200 | | otherwise = dflags1
|
| 201 | 201 | where def_ghci_flags = dflags1 `gopt_set` Opt_ImplicitImportQualified
|
| 202 | + `gopt_set` Opt_InteractiveErrorHints
|
|
| 202 | 203 | `gopt_set` Opt_IgnoreOptimChanges
|
| 203 | 204 | `gopt_set` Opt_IgnoreHpcChanges
|
| 204 | 205 | -- Setting this by default has the nice effect that
|
| ... | ... | @@ -14,6 +14,7 @@ other dynamic, non-language, flag settings: |
| 14 | 14 | -fno-unoptimized-core-for-interpreter
|
| 15 | 15 | -fshow-warning-groups
|
| 16 | 16 | -fprefer-byte-code
|
| 17 | + -finteractive-error-hints
|
|
| 17 | 18 | -fbreak-points
|
| 18 | 19 | warning settings:
|
| 19 | 20 | -Wpattern-namespace-specifier
|
| ... | ... | @@ -33,6 +34,7 @@ other dynamic, non-language, flag settings: |
| 33 | 34 | -fno-unoptimized-core-for-interpreter
|
| 34 | 35 | -fshow-warning-groups
|
| 35 | 36 | -fprefer-byte-code
|
| 37 | + -finteractive-error-hints
|
|
| 36 | 38 | -fbreak-points
|
| 37 | 39 | warning settings:
|
| 38 | 40 | -Wpattern-namespace-specifier
|
| ... | ... | @@ -50,6 +52,7 @@ other dynamic, non-language, flag settings: |
| 50 | 52 | -fno-unoptimized-core-for-interpreter
|
| 51 | 53 | -fshow-warning-groups
|
| 52 | 54 | -fprefer-byte-code
|
| 55 | + -finteractive-error-hints
|
|
| 53 | 56 | -fbreak-points
|
| 54 | 57 | warning settings:
|
| 55 | 58 | -Wpattern-namespace-specifier
|
| ... | ... | @@ -67,6 +70,7 @@ other dynamic, non-language, flag settings: |
| 67 | 70 | -fno-unoptimized-core-for-interpreter
|
| 68 | 71 | -fshow-warning-groups
|
| 69 | 72 | -fprefer-byte-code
|
| 73 | + -finteractive-error-hints
|
|
| 70 | 74 | -fbreak-points
|
| 71 | 75 | warning settings:
|
| 72 | 76 | -Wpattern-namespace-specifier
|
| ... | ... | @@ -84,6 +88,7 @@ other dynamic, non-language, flag settings: |
| 84 | 88 | -fno-unoptimized-core-for-interpreter
|
| 85 | 89 | -fshow-warning-groups
|
| 86 | 90 | -fprefer-byte-code
|
| 91 | + -finteractive-error-hints
|
|
| 87 | 92 | -fbreak-points
|
| 88 | 93 | warning settings:
|
| 89 | 94 | -Wpattern-namespace-specifier |
| ... | ... | @@ -12,6 +12,7 @@ other dynamic, non-language, flag settings: |
| 12 | 12 | -fimplicit-import-qualified
|
| 13 | 13 | -fshow-warning-groups
|
| 14 | 14 | -fprefer-byte-code
|
| 15 | + -finteractive-error-hints
|
|
| 15 | 16 | -fbreak-points
|
| 16 | 17 | warning settings:
|
| 17 | 18 | -Wpattern-namespace-specifier
|
| ... | ... | @@ -12,6 +12,7 @@ other dynamic, non-language, flag settings: |
| 12 | 12 | -fimplicit-import-qualified
|
| 13 | 13 | -fshow-warning-groups
|
| 14 | 14 | -fprefer-byte-code
|
| 15 | + -finteractive-error-hints
|
|
| 15 | 16 | -fbreak-points
|
| 16 | 17 | warning settings:
|
| 17 | 18 | -Wpattern-namespace-specifier
|