[Git][ghc/ghc][master] Compute all emitted diagnostic codes
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Wed Aug 9 01:27:20 UTC 2023
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
0ef1d8ae by sheaf at 2023-08-08T21:26:51-04:00
Compute all emitted diagnostic codes
This commit introduces in GHC.Types.Error.Codes the function
constructorCodes :: forall diag. (...) => Map DiagnosticCode String
which computes a collection of all the diagnostic codes that correspond
to a particular type. In particular, we can compute the collection of
all diagnostic codes emitted by GHC using the invocation
constructorCodes @GhcMessage
We then make use of this functionality in the new "codes" test which
checks consistency and coverage of GHC diagnostic codes.
It performs three checks:
- check 1: all non-outdated GhcDiagnosticCode equations
are statically used.
- check 2: all outdated GhcDiagnosticCode equations
are statically unused.
- check 3: all statically used diagnostic codes are covered by
the testsuite (modulo accepted exceptions).
- - - - -
21 changed files:
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/HsToCore/Errors/Ppr.hs
- compiler/GHC/Iface/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Types/Error.hs
- compiler/GHC/Types/Error/Codes.hs
- hadrian/src/Packages.hs
- hadrian/src/Rules/Test.hs
- hadrian/src/Settings/Default.hs
- + linters/lint-codes/LintCodes/Coverage.hs
- + linters/lint-codes/LintCodes/Static.hs
- + linters/lint-codes/Main.hs
- + linters/lint-codes/Makefile
- + linters/lint-codes/cabal.project
- + linters/lint-codes/ghc.mk
- + linters/lint-codes/lint-codes.cabal
- testsuite/mk/boilerplate.mk
- + testsuite/tests/diagnostic-codes/Makefile
- + testsuite/tests/diagnostic-codes/all.T
- + testsuite/tests/diagnostic-codes/codes.stdout
Changes:
=====================================
compiler/GHC/Driver/Errors/Ppr.hs
=====================================
@@ -17,7 +17,7 @@ import GHC.Driver.DynFlags
import GHC.HsToCore.Errors.Ppr ()
import GHC.Parser.Errors.Ppr ()
import GHC.Types.Error
-import GHC.Types.Error.Codes ( constructorCode )
+import GHC.Types.Error.Codes
import GHC.Unit.Types
import GHC.Utils.Outputable
import GHC.Unit.Module
=====================================
compiler/GHC/HsToCore/Errors/Ppr.hs
=====================================
@@ -15,7 +15,7 @@ import GHC.HsToCore.Errors.Types
import GHC.Prelude
import GHC.Types.Basic (pprRuleName)
import GHC.Types.Error
-import GHC.Types.Error.Codes ( constructorCode )
+import GHC.Types.Error.Codes
import GHC.Types.Id (idType)
import GHC.Types.SrcLoc
import GHC.Utils.Misc
=====================================
compiler/GHC/Iface/Errors/Ppr.hs
=====================================
@@ -31,7 +31,7 @@ import GHC.Prelude
import GHC.Types.Error
import GHC.Types.Hint.Ppr () -- Outputable GhcHint
-import GHC.Types.Error.Codes ( constructorCode )
+import GHC.Types.Error.Codes
import GHC.Types.Name
import GHC.Types.TyThing
=====================================
compiler/GHC/Parser/Errors/Ppr.hs
=====================================
@@ -22,7 +22,7 @@ import GHC.Types.Hint
import GHC.Types.Error
import GHC.Types.Hint.Ppr (perhapsAsPat)
import GHC.Types.SrcLoc
-import GHC.Types.Error.Codes ( constructorCode )
+import GHC.Types.Error.Codes
import GHC.Types.Name.Reader ( opIsAt, rdrNameOcc, mkUnqual )
import GHC.Types.Name.Occurrence (isSymOcc, occNameFS, varName)
import GHC.Utils.Outputable
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -74,7 +74,7 @@ import GHC.Types.Error
import GHC.Types.Hint
import GHC.Types.Hint.Ppr () -- Outputable GhcHint
import GHC.Types.Basic
-import GHC.Types.Error.Codes ( constructorCode )
+import GHC.Types.Error.Codes
import GHC.Types.Id
import GHC.Types.Id.Info ( RecSelParent(..) )
import GHC.Types.Name
@@ -3113,7 +3113,6 @@ instance Diagnostic TcRnMessage where
TcRnIllegalTypeExpr{}
-> noHints
- diagnosticCode :: TcRnMessage -> Maybe DiagnosticCode
diagnosticCode = constructorCode
-- | Change [x] to "x", [x, y] to "x and y", [x, y, z] to "x, y, and z",
=====================================
compiler/GHC/Types/Error.hs
=====================================
@@ -113,10 +113,8 @@ import Data.Typeable ( Typeable )
import Numeric.Natural ( Natural )
import Text.Printf ( printf )
-{-
-Note [Messages]
-~~~~~~~~~~~~~~~
-
+{- Note [Messages]
+~~~~~~~~~~~~~~~~~~
We represent the 'Messages' as a single bag of warnings and errors.
The reason behind that is that there is a fluid relationship between errors
@@ -809,8 +807,11 @@ data DiagnosticCode =
, diagnosticCodeNumber :: Natural
-- ^ the actual diagnostic code
}
+ deriving ( Eq, Ord )
-instance Outputable DiagnosticCode where
- ppr (DiagnosticCode prefix c) =
- text prefix <> text "-" <> text (printf "%05d" c)
+instance Show DiagnosticCode where
+ show (DiagnosticCode prefix c) =
+ prefix ++ "-" ++ printf "%05d" c
-- pad the numeric code to have at least 5 digits
+instance Outputable DiagnosticCode where
+ ppr code = text (show code)
=====================================
compiler/GHC/Types/Error/Codes.hs
=====================================
@@ -16,7 +16,7 @@
-- A diagnostic code is a numeric unique identifier for a diagnostic.
-- See Note [Diagnostic codes].
module GHC.Types.Error.Codes
- ( constructorCode )
+ ( GhcDiagnosticCode, constructorCode, constructorCodes )
where
import GHC.Prelude
@@ -36,9 +36,13 @@ import GHC.Utils.Panic.Plain
import Data.Kind ( Type, Constraint )
import GHC.Exts ( proxy# )
import GHC.Generics
-import GHC.TypeLits ( Symbol, TypeError, ErrorMessage(..) )
+import GHC.TypeLits ( Symbol, KnownSymbol, symbolVal'
+ , TypeError, ErrorMessage(..) )
import GHC.TypeNats ( Nat, KnownNat, natVal' )
+import Data.Map.Strict ( Map )
+import qualified Data.Map.Strict as Map
+
{- Note [Diagnostic codes]
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -110,6 +114,18 @@ constructorCode :: (Generic diag, GDiagnosticCode (Rep diag))
=> diag -> Maybe DiagnosticCode
constructorCode diag = gdiagnosticCode (from diag)
+-- | This function computes all diagnostic codes that occur inside a given
+-- type using generics and the 'GhcDiagnosticCode' type family.
+--
+-- For example, if @T = MkT1 | MkT2@, @GhcDiagnosticCode \"MkT1\" = 123@ and
+-- @GhcDiagnosticCode \"MkT2\" = 456@, then we will get
+-- > constructorCodes @T = fromList [ (123, \"MkT1\"), (456, \"MkT2\") ]
+constructorCodes :: forall diag. (Generic diag, GDiagnosticCodes '[diag] (Rep diag))
+ => Map DiagnosticCode String
+constructorCodes = gdiagnosticCodes @'[diag] @(Rep diag)
+ -- See Note [diagnosticCodes: don't recur into already-seen types]
+ -- for the @'[diag] type argument.
+
-- | Type family computing the numeric diagnostic code for a given error message constructor.
--
-- Its injectivity annotation ensures uniqueness of error codes.
@@ -479,7 +495,6 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnIllegalHsigDefaultMethods" = 93006
GhcDiagnosticCode "TcRnHsigFixityMismatch" = 93007
- GhcDiagnosticCode "TcRnHsigNoIface" = 93010
GhcDiagnosticCode "TcRnHsigMissingModuleExport" = 93011
GhcDiagnosticCode "TcRnBadGenericMethod" = 59794
GhcDiagnosticCode "TcRnWarningMinimalDefIncomplete" = 13511
@@ -488,7 +503,6 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnBadMethodErr" = 46284
GhcDiagnosticCode "TcRnIllegalTypeData" = 15013
GhcDiagnosticCode "TcRnTypeDataForbids" = 67297
- GhcDiagnosticCode "TcRnInterfaceLookupError" = 52243
GhcDiagnosticCode "TcRnUnsatisfiedMinimalDef" = 06201
GhcDiagnosticCode "TcRnMisplacedInstSig" = 06202
GhcDiagnosticCode "TcRnCapturedTermName" = 54201
@@ -864,21 +878,29 @@ type family GhcDiagnosticCode c = n | n -> c where
-- and this includes outdated diagnostic codes for errors that GHC
-- no longer reports. These are collected below.
- GhcDiagnosticCode "TcRnIllegalInstanceHeadDecl" = 12222
- GhcDiagnosticCode "TcRnNoClassInstHead" = 56538
+ GhcDiagnosticCode "TcRnIllegalInstanceHeadDecl" = Outdated 12222
+ GhcDiagnosticCode "TcRnNoClassInstHead" = Outdated 56538
-- The above two are subsumed by InstHeadNonClass [GHC-53946]
- GhcDiagnosticCode "TcRnNameByTemplateHaskellQuote" = 40027
- GhcDiagnosticCode "TcRnIllegalBindingOfBuiltIn" = 69639
- GhcDiagnosticCode "TcRnMixedSelectors" = 40887
- GhcDiagnosticCode "TcRnBadBootFamInstDecl" = 06203
- GhcDiagnosticCode "TcRnBindInBootFile" = 11247
- GhcDiagnosticCode "TcRnUnexpectedTypeSplice" = 39180
- GhcDiagnosticCode "PsErrUnexpectedTypeAppInDecl" = 45054
- GhcDiagnosticCode "TcRnUnpromotableThing" = 88634
- GhcDiagnosticCode "UntouchableVariable" = 34699
- GhcDiagnosticCode "TcRnBindVarAlreadyInScope" = 69710
- GhcDiagnosticCode "TcRnBindMultipleVariables" = 92957
+ GhcDiagnosticCode "TcRnNameByTemplateHaskellQuote" = Outdated 40027
+ GhcDiagnosticCode "TcRnIllegalBindingOfBuiltIn" = Outdated 69639
+ GhcDiagnosticCode "TcRnMixedSelectors" = Outdated 40887
+ GhcDiagnosticCode "TcRnBadBootFamInstDecl" = Outdated 06203
+ GhcDiagnosticCode "TcRnBindInBootFile" = Outdated 11247
+ GhcDiagnosticCode "TcRnUnexpectedTypeSplice" = Outdated 39180
+ GhcDiagnosticCode "PsErrUnexpectedTypeAppInDecl" = Outdated 45054
+ GhcDiagnosticCode "TcRnUnpromotableThing" = Outdated 88634
+ GhcDiagnosticCode "UntouchableVariable" = Outdated 34699
+ GhcDiagnosticCode "TcRnBindVarAlreadyInScope" = Outdated 69710
+ GhcDiagnosticCode "TcRnBindMultipleVariables" = Outdated 92957
+ GhcDiagnosticCode "TcRnHsigNoIface" = Outdated 93010
+ GhcDiagnosticCode "TcRnInterfaceLookupError" = Outdated 52243
+
+-- | Use this type synonym to mark a diagnostic code as outdated.
+--
+-- The presence of this type synonym is used by the 'codes' test to determine
+-- which diagnostic codes to check for testsuite coverage.
+type Outdated a = a
{- *********************************************************************
* *
@@ -1106,12 +1128,26 @@ To achieve this, we use a variant of the 'typed' lens from 'generic-lens'
type GDiagnosticCode :: (Type -> Type) -> Constraint
class GDiagnosticCode f where
gdiagnosticCode :: f a -> Maybe DiagnosticCode
+-- | Use the generic representation of a type to retrieve the collection
+-- of all diagnostic codes it can give rise to.
+type GDiagnosticCodes :: [Type] -> (Type -> Type) -> Constraint
+class GDiagnosticCodes seen f where
+ gdiagnosticCodes :: Map DiagnosticCode String
-type ConstructorCode :: Symbol -> (Type -> Type) -> Maybe Type -> Constraint
+type ConstructorCode :: Symbol -> (Type -> Type) -> Maybe Type -> Constraint
class ConstructorCode con f recur where
gconstructorCode :: f a -> Maybe DiagnosticCode
-instance KnownConstructor con => ConstructorCode con f 'Nothing where
+type ConstructorCodes :: Symbol -> (Type -> Type) -> [Type] -> Maybe Type -> Constraint
+class ConstructorCodes con f seen recur where
+ gconstructorCodes :: Map DiagnosticCode String
+
+instance (KnownConstructor con, KnownSymbol con) => ConstructorCode con f 'Nothing where
gconstructorCode _ = Just $ DiagnosticCode "GHC" $ natVal' @(GhcDiagnosticCode con) proxy#
+instance (KnownConstructor con, KnownSymbol con) => ConstructorCodes con f seen 'Nothing where
+ gconstructorCodes =
+ Map.singleton
+ (DiagnosticCode "GHC" $ natVal' @(GhcDiagnosticCode con) proxy#)
+ (symbolVal' @con proxy#)
-- If we recur into the 'UnknownDiagnostic' existential datatype,
-- unwrap the existential and obtain the error code.
@@ -1121,30 +1157,51 @@ instance {-# OVERLAPPING #-}
=> ConstructorCode con f ('Just (UnknownDiagnostic opts)) where
gconstructorCode diag = case getType @(UnknownDiagnostic opts) @con @f diag of
UnknownDiagnostic _ diag -> diagnosticCode diag
+instance {-# OVERLAPPING #-}
+ ( ConRecursInto con ~ 'Just (UnknownDiagnostic opts) )
+ => ConstructorCodes con f seen ('Just (UnknownDiagnostic opts)) where
+ gconstructorCodes = Map.empty
-- (*) Recursive instance: Recur into the given type.
instance ( ConRecursInto con ~ 'Just ty, HasType ty con f
, Generic ty, GDiagnosticCode (Rep ty) )
=> ConstructorCode con f ('Just ty) where
- gconstructorCode diag = constructorCode (getType @ty @con @f diag)
+ gconstructorCode diag = gdiagnosticCode (from $ getType @ty @con @f diag)
+instance ( ConRecursInto con ~ 'Just ty, HasType ty con f
+ , Generic ty, GDiagnosticCodes (Insert ty seen) (Rep ty)
+ , Seen seen ty )
+ => ConstructorCodes con f seen ('Just ty) where
+ gconstructorCodes =
+ -- See Note [diagnosticCodes: don't recur into already-seen types]
+ if wasSeen @seen @ty
+ then Map.empty
+ else gdiagnosticCodes @(Insert ty seen) @(Rep ty)
-- (**) Constructor instance: handle constructors directly.
--
-- Obtain the code from the 'GhcDiagnosticCode'
-- type family, applied to the name of the constructor.
-instance (ConstructorCode con f recur, recur ~ ConRecursInto con)
+instance (ConstructorCode con f recur, recur ~ ConRecursInto con, KnownSymbol con)
=> GDiagnosticCode (M1 i ('MetaCons con x y) f) where
gdiagnosticCode (M1 x) = gconstructorCode @con @f @recur x
+instance (ConstructorCodes con f seen recur, recur ~ ConRecursInto con, KnownSymbol con)
+ => GDiagnosticCodes seen (M1 i ('MetaCons con x y) f) where
+ gdiagnosticCodes = gconstructorCodes @con @f @seen @recur
-- Handle sum types (the diagnostic types are sums of constructors).
instance (GDiagnosticCode f, GDiagnosticCode g) => GDiagnosticCode (f :+: g) where
gdiagnosticCode (L1 x) = gdiagnosticCode @f x
gdiagnosticCode (R1 y) = gdiagnosticCode @g y
+instance (GDiagnosticCodes seen f, GDiagnosticCodes seen g) => GDiagnosticCodes seen (f :+: g) where
+ gdiagnosticCodes = Map.union (gdiagnosticCodes @seen @f) (gdiagnosticCodes @seen @g)
-- Discard metadata we don't need.
instance GDiagnosticCode f
=> GDiagnosticCode (M1 i ('MetaData nm mod pkg nt) f) where
gdiagnosticCode (M1 x) = gdiagnosticCode @f x
+instance GDiagnosticCodes seen f
+ => GDiagnosticCodes seen (M1 i ('MetaData nm mod pkg nt) f) where
+ gdiagnosticCodes = gdiagnosticCodes @seen @f
-- | Decide whether to pick the left or right branch
-- when deciding how to recurse into a product.
@@ -1196,6 +1253,50 @@ instance HasType ty orig f => HasTypeProd ty ('Just l) orig f g where
instance HasType ty orig g => HasTypeProd ty 'Nothing orig f g where
getTypeProd (_ :*: y) = getType @ty @orig @g y
+{- Note [diagnosticCodes: don't recur into already-seen types]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When traversing through the Generic representation of a datatype to compute all
+of the corresponding error codes, we need to keep track of types we have already
+seen in order to avoid a runtime loop.
+
+For example, TcRnMessage is defined recursively in terms of itself:
+
+ data TcRnMessage where
+ ...
+ TcRnMessageWithInfo :: !UnitState
+ -> !TcRnMessageDetailed -- contains a TcRnMessage
+ -> TcRnMessage
+
+If we naively computed the collection of error codes, we would get a computation
+of the form
+
+ diagnosticCodes @TcRnMessage = ... `Map.union` constructorCodes "TcRnMessageWithInfo"
+ constructorCodes "TcRnMessageWithInfo" = diagnosticCodes @TcRnMessage
+
+This would cause an infinite loop. We thus keep track of a list of types we
+have already encountered, and when we recur into a type we have already
+encountered, we simply skip taking that union (see (*)).
+
+Note that 'constructorCodes' starts by marking the initial type itself as "seen",
+which precisely avoids the loop above when calling 'constructorCodes @TcRnMessage'.
+-}
+
+type Seen :: [Type] -> Type -> Constraint
+class Seen seen ty where
+ wasSeen :: Bool
+instance Seen '[] ty where
+ wasSeen = False
+instance {-# OVERLAPPING #-} Seen (ty ': tys) ty where
+ wasSeen = True
+instance Seen tys ty => Seen (ty' ': tys) ty where
+ wasSeen = wasSeen @tys @ty
+
+type Insert :: Type -> [Type] -> [Type]
+type family Insert ty tys where
+ Insert ty '[] = '[ty]
+ Insert ty (ty ': tys) = ty ': tys
+ Insert ty (ty' ': tys) = ty' ': Insert ty tys
+
{- *********************************************************************
* *
Custom type errors for diagnostic codes
=====================================
hadrian/src/Packages.hs
=====================================
@@ -11,7 +11,7 @@ module Packages (
libffi, mtl, parsec, pretty, primitive, process, remoteIserv, rts,
runGhc, semaphoreCompat, stm, templateHaskell, terminfo, text, time, timeout, touchy,
transformers, unlit, unix, win32, xhtml,
- lintersCommon, lintNotes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace,
+ lintersCommon, lintNotes, lintCodes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace,
ghcPackages, isGhcPackage,
-- * Package information
@@ -45,7 +45,7 @@ ghcPackages =
, terminfo, text, time, touchy, transformers, unlit, unix, win32, xhtml
, timeout
, lintersCommon
- , lintNotes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace ]
+ , lintNotes, lintCodes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace ]
-- TODO: Optimise by switching to sets of packages.
isGhcPackage :: Package -> Bool
@@ -61,7 +61,7 @@ array, base, binary, bytestring, cabalSyntax, cabal, checkPpr, checkExact, count
parsec, pretty, primitive, process, rts, runGhc, semaphoreCompat, stm, templateHaskell,
terminfo, text, time, touchy, transformers, unlit, unix, win32, xhtml,
timeout,
- lintersCommon, lintNotes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace
+ lintersCommon, lintNotes, lintCodes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace
:: Package
array = lib "array"
base = lib "base"
@@ -133,6 +133,7 @@ xhtml = lib "xhtml"
lintersCommon = lib "linters-common" `setPath` "linters/linters-common"
lintNotes = linter "lint-notes"
+lintCodes = linter "lint-codes"
lintCommitMsg = linter "lint-commit-msg"
lintSubmoduleRefs = linter "lint-submodule-refs"
lintWhitespace = linter "lint-whitespace"
=====================================
hadrian/src/Rules/Test.hs
=====================================
@@ -55,6 +55,12 @@ noteLinterSourcePath = "linters/lint-notes/Main.hs"
noteLinterExtra :: [String]
noteLinterExtra = ["-ilinters/lint-notes"]
+codeLinterProgPath, codeLinterSourcePath :: FilePath
+codeLinterProgPath = "test/bin/lint-codes" <.> exe
+codeLinterSourcePath = "linters/lint-codes/Main.hs"
+codeLinterExtra :: [String]
+codeLinterExtra = ["-ilinters/lint-codes"]
+
whitespaceLinterProgPath, whitespaceLinterSourcePath :: FilePath
whitespaceLinterProgPath = "test/bin/lint-whitespace" <.> exe
whitespaceLinterSourcePath = "linters/lint-whitespace/Main.hs"
@@ -78,6 +84,7 @@ checkPrograms =
, CheckProgram "test:count-deps" countDepsProgPath countDepsSourcePath countDepsExtra countDeps id id
, CheckProgram "test:dump-decls" dumpDeclsProgPath dumpDeclsSourcePath dumpDeclsExtra dumpDecls id id
, CheckProgram "lint:notes" noteLinterProgPath noteLinterSourcePath noteLinterExtra lintNotes (const stage0Boot) id
+ , CheckProgram "lint:codes" codeLinterProgPath codeLinterSourcePath codeLinterExtra lintCodes id id
, CheckProgram "lint:whitespace" whitespaceLinterProgPath whitespaceLinterSourcePath whitespaceLinterExtra lintWhitespace (const stage0Boot) (filter (/= lintersCommon))
]
@@ -273,6 +280,7 @@ testRules = do
setEnv "DUMP_DECLS" (top -/- root -/- dumpDeclsProgPath)
setEnv "COUNT_DEPS" (top -/- root -/- countDepsProgPath)
setEnv "LINT_NOTES" (top -/- root -/- noteLinterProgPath)
+ setEnv "LINT_CODES" (top -/- root -/- codeLinterProgPath)
setEnv "LINT_WHITESPACE" (top -/- root -/- whitespaceLinterProgPath)
-- This lets us bypass the need to generate a config
=====================================
hadrian/src/Settings/Default.hs
=====================================
@@ -65,7 +65,15 @@ defaultBignumBackend = "gmp"
-- packages in StageBoot so if you also need to distribute anything here then add
-- it to `stage0packages` or `stage1packages` as appropiate.
stageBootPackages :: Action [Package]
-stageBootPackages = return [lintersCommon, lintCommitMsg, lintSubmoduleRefs, lintWhitespace, lintNotes, hsc2hs, compareSizes, deriveConstants, genapply, genprimopcode, unlit ]
+stageBootPackages = return
+ [ lintersCommon, lintCommitMsg, lintSubmoduleRefs, lintWhitespace, lintNotes
+ , hsc2hs
+ , compareSizes
+ , deriveConstants
+ , genapply
+ , genprimopcode
+ , unlit
+ ]
-- | Packages built in 'Stage0' by default. You can change this in "UserSettings".
stage0Packages :: Action [Package]
@@ -170,7 +178,7 @@ stage2Packages = stage1Packages
-- | Packages that are built only for the testsuite.
testsuitePackages :: Action [Package]
-testsuitePackages = return ([ timeout | windowsHost ] ++ [ checkPpr, checkExact, countDeps, ghcConfig, dumpDecls ])
+testsuitePackages = return ([ timeout | windowsHost ] ++ [ checkPpr, checkExact, countDeps, lintCodes, ghcConfig, dumpDecls ])
-- | Default build ways for library packages:
-- * We always build 'vanilla' way.
=====================================
linters/lint-codes/LintCodes/Coverage.hs
=====================================
@@ -0,0 +1,46 @@
+module LintCodes.Coverage
+ ( getCoveredCodes )
+ where
+
+-- containers
+import Data.Set
+ ( Set )
+import qualified Data.Set as Set
+ ( fromList )
+
+-- ghc
+import GHC.Types.Error
+ ( DiagnosticCode(..) )
+
+-- process
+import System.Process
+ ( readProcess )
+
+--------------------------------------------------------------------------------
+-- Diagnostic code coverage from testsuite .stdout and .stderr files
+
+-- | Get all diagnostic codes that appear in testsuite .stdout and .stderr
+-- files.
+getCoveredCodes :: IO (Set DiagnosticCode)
+getCoveredCodes =
+ -- Run git grep on .stdout and .stderr files in the testsuite subfolder.
+ do { codes <- lines
+ <$> readProcess "git"
+ [ "grep", "-oh", codeRegex
+ -- -oh: only show the match, and omit the filename.
+ , "--", ":/testsuite/*.stdout", ":/testsuite/*.stderr"
+ , ":!*/codes.stdout" -- Don't include the output of this test itself.
+ ] ""
+ ; return $ Set.fromList $ map parseCode codes }
+
+-- | Regular expression to parse a diagnostic code.
+codeRegex :: String
+codeRegex = "\\[[A-Za-z]\\+-[0-9]\\+\\]"
+
+-- | Turn a string that matches the 'codeRegex' regular expression
+-- into its corresponding 'DiagnosticCode'.
+parseCode :: String -> DiagnosticCode
+parseCode c =
+ case break (== '-') $ drop 1 c of
+ (ns, rest) ->
+ DiagnosticCode ns ( read $ init $ drop 1 rest )
=====================================
linters/lint-codes/LintCodes/Static.hs
=====================================
@@ -0,0 +1,179 @@
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralisedNewtypeDeriving #-}
+{-# LANGUAGE TypeApplications #-}
+
+module LintCodes.Static
+ ( FamEqnIndex, Use(..), used, outdated
+ , getFamEqnCodes
+ , staticallyUsedCodes
+ )
+ where
+
+-- base
+import Data.Maybe
+ ( listToMaybe )
+import System.Environment
+ ( getArgs )
+
+-- containers
+import Data.Map.Strict
+ ( Map )
+import qualified Data.Map.Strict as Map
+ ( fromList )
+
+-- transformers
+import Control.Monad.IO.Class
+ ( liftIO )
+
+-- ghc
+import GHC.Driver.Errors.Types
+ ( GhcMessage )
+import GHC.Types.Error
+ ( DiagnosticCode(..) )
+import GHC.Types.Error.Codes
+ ( constructorCodes )
+
+-- ghc (API usage)
+import GHC
+ ( runGhc, parseDynamicFlags
+ , getSessionDynFlags, setSessionDynFlags
+ , getSession, getLogger
+ , noLoc
+ )
+import GHC.Core.Coercion.Axiom
+ ( CoAxBranch(..), coAxiomBranches, fromBranches )
+import GHC.Core.TyCon
+ ( TyCon, tyConName
+ , isClosedSynFamilyTyConWithAxiom_maybe
+ )
+import qualified GHC.Core.TyCo.Rep as GHC
+ ( Type )
+import GHC.Core.Type
+ ( isNumLitTy, isStrLitTy
+ , splitTyConAppNoView_maybe
+ )
+import GHC.Data.FastString
+ ( unpackFS )
+import GHC.Driver.Env
+ ( lookupType )
+import GHC.Iface.Env
+ ( lookupOrig )
+import GHC.Iface.Load
+ ( WhereFrom(..), loadInterface )
+import GHC.Types.Name
+ ( nameOccName, occNameFS )
+import GHC.Types.Name.Occurrence
+ ( mkTcOcc )
+import GHC.Types.TyThing
+ ( TyThing(..) )
+import GHC.Types.PkgQual
+ ( PkgQual(..) )
+import GHC.Tc.Utils.Monad
+ ( initIfaceLoad )
+import GHC.Unit.Finder
+ ( FindResult(..), findImportedModule )
+import GHC.Utils.Outputable
+ ( text )
+import Language.Haskell.Syntax.Module.Name
+ ( mkModuleName )
+
+--------------------------------------------------------------------------------
+
+-- | The diagnostic codes that are statically reachable from the
+-- 'GhcMessage' datatype.
+staticallyUsedCodes :: Map DiagnosticCode String
+staticallyUsedCodes = constructorCodes @GhcMessage
+
+--------------------------------------------------------------------------------
+
+-- | The index of an equation of the 'GhcDiagnosticCode' type family,
+-- starting from '1'.
+newtype FamEqnIndex = FamEqnIndex Int
+ deriving newtype ( Eq, Ord )
+ deriving stock Show
+-- | Whether an equation of the 'GhcDiagnosticCode' type family is still
+-- statically used, or whether it corresponds to an outdated diagnostic code
+-- that GHC previously emitted but no longer does.
+data Use = Used | Outdated
+ deriving stock ( Eq, Show )
+
+used, outdated :: ( FamEqnIndex, String, Use ) -> Maybe ( FamEqnIndex, String )
+used ( i, con, Used ) = Just ( i, con )
+used _ = Nothing
+outdated ( i, con, Outdated ) = Just ( i, con )
+outdated _ = Nothing
+
+--------------------------------------------------------------------------------
+-- Use the GHC API to obtain the 'TyCon' for the 'GhcDiagnosticCode' type
+-- family, and inspect its equations.
+-- It would also be possible to use Template Haskell reification, but usage
+-- of Template Haskell at compile-time is problematic for Hadrian.
+
+-- | The diagnostic codes returned by the 'GhcDiagnosticCode' type family.
+getFamEqnCodes :: IO ( Map DiagnosticCode ( FamEqnIndex, String, Use ) )
+getFamEqnCodes =
+ do { tc <- ghcDiagnosticCodeTyCon
+ ; return $ case isClosedSynFamilyTyConWithAxiom_maybe tc of
+ { Nothing -> error "can't find equations for 'GhcDiagnosticCode'"
+ ; Just ax -> Map.fromList
+ $ zipWith parseBranch [1..]
+ $ fromBranches $ coAxiomBranches ax
+ } }
+
+parseBranch :: Int -> CoAxBranch -> ( DiagnosticCode, ( FamEqnIndex, String, Use ) )
+parseBranch i ( CoAxBranch { cab_lhs = lhs, cab_rhs = rhs })
+ | [ con ] <- lhs
+ , Just con_fs <- isStrLitTy con
+ , let con_str = unpackFS con_fs
+ (code, use) = parseBranchRHS rhs
+ = ( DiagnosticCode "GHC" ( fromInteger code ), ( FamEqnIndex i, con_str, use ) )
+ | otherwise
+ = error "couldn't parse equation of 'GhcDiagnosticCode'"
+
+parseBranchRHS :: GHC.Type -> ( Integer, Use )
+parseBranchRHS rhs
+ | Just code <- isNumLitTy rhs
+ = ( code, use )
+ | otherwise
+ = error "couldn't parse equation RHS of 'GhcDiagnosticCode'"
+ where
+ use
+ | Just (tc,_) <- splitTyConAppNoView_maybe rhs
+ , unpackFS (occNameFS (nameOccName (tyConName tc))) == "Outdated"
+ = Outdated
+ | otherwise
+ = Used
+
+-- | Look up the 'GhcDiagnosticCode' type family using the GHC API.
+ghcDiagnosticCodeTyCon :: IO TyCon
+ghcDiagnosticCodeTyCon =
+ do { args <- getArgs
+ ; runGhc (listToMaybe args)
+
+ -- STEP 1: start a GHC API session with "-package ghc"
+ do { dflags1 <- getSessionDynFlags
+ ; let opts = map noLoc ["-package ghc"]
+ ; logger <- getLogger
+ ; (dflags2, _,_) <- parseDynamicFlags logger dflags1 opts
+ ; setSessionDynFlags dflags2
+ ; hsc_env <- getSession
+ ; liftIO
+
+ -- STEP 2: look up the module "GHC.Types.Error.Codes"
+ do { res <- findImportedModule hsc_env (mkModuleName "GHC.Types.Error.Codes") NoPkgQual
+ ; case res of
+ { Found _ modl ->
+
+ -- STEP 3: look up the 'GhcDiagnosticCode' type family.
+ do { nm <- initIfaceLoad hsc_env do
+ _ <- loadInterface (text "lint-codes: need 'GhcDiagnosticCode'")
+ modl ImportBySystem
+ lookupOrig modl $ mkTcOcc "GhcDiagnosticCode"
+ ; mb_tyThing <- lookupType hsc_env nm
+ ; return $ case mb_tyThing of
+ Just (ATyCon tc) -> tc
+ _ -> error "lint-codes: failed to look up TyCon for 'GhcDiagnosticCode'"
+ }
+
+ ; _ -> error "lint-codes: failed to find 'GHC.Types.Error.Codes'" } } } }
=====================================
linters/lint-codes/Main.hs
=====================================
@@ -0,0 +1,158 @@
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE TupleSections #-}
+
+module Main where
+
+-- base
+import Control.Monad
+ ( when )
+import Data.List
+ ( sortOn )
+import Text.Printf
+ ( printf )
+
+-- containers
+import Data.Map.Strict
+ ( Map )
+import qualified Data.Map.Strict as Map
+ ( (\\), intersection, mapMaybe, toList, withoutKeys )
+
+-- ghc
+import GHC.Types.Error
+ ( DiagnosticCode(..) )
+
+-- lint-codes
+import LintCodes.Static
+ ( FamEqnIndex, used, outdated
+ , getFamEqnCodes
+ , staticallyUsedCodes
+ )
+import LintCodes.Coverage
+ ( getCoveredCodes )
+
+--------------------------------------------------------------------------------
+
+main :: IO ()
+main = do
+
+ ------------------------------
+ -- Static consistency checks.
+ famEqnCodes <- getFamEqnCodes
+
+ let
+ familyEqnUsedCodes = Map.mapMaybe used famEqnCodes
+ familyEqnOutdatedCodes = Map.mapMaybe outdated famEqnCodes
+
+ -- Consistency of diagnostic codes:
+ -- all diagnostic codes returned by the 'GhcDiagnosticCode' type family
+ -- should be statically used, unless they are marked as outdated.
+ staticallyUnusedCodes = familyEqnUsedCodes Map.\\ staticallyUsedCodes
+
+ -- Consistency of outdated diagnostic codes:
+ -- if a diagnostic code is marked as outdated, it should not be statically used.
+ outdatedStaticallyUsedCodes =
+ familyEqnOutdatedCodes `Map.intersection` staticallyUsedCodes
+
+ -- Test 1: all non-outdated 'GhcDiagnosticCode' equations are statically used.
+ let plural1 = length staticallyUnusedCodes > 1
+ test1OK :: Bool
+ test1Message :: String
+ (test1OK, test1Message)
+ | null staticallyUnusedCodes
+ = (True,) $
+ "- All non-outdated 'GhcDiagnosticCode' equations are statically used."
+ | otherwise
+ = (False,) $
+ unlines [ "- The following 'GhcDiagnosticCode' equation" ++ (if plural1 then "s appear" else " appears") ++ " to be unused."
+ , " If " ++ (if plural1 then "any of these codes are indeed no longer used, but were"
+ else "this code is indeed no longer used, but was")
+ , " emitted by a previous version of GHC, you should mark " ++ (if plural1 then "them" else "it") ++ " as outdated"
+ , " by tagging the RHS of the appropriate type family equation of"
+ , " the 'GhcDiagnosticCode' type family in 'GHC.Types.Error.Codes'"
+ , " with the 'Outdated' type synonym."
+ , ""
+ , showDiagnosticCodesWith printUnused staticallyUnusedCodes
+ ]
+ putStrLn ""
+ putStrLn test1Message
+ putStrLn ""
+
+ -- Test 2: all outdated 'GhcDiagnosticCode' equations are statically unused.
+ let plural2 = length outdatedStaticallyUsedCodes > 1
+ test2OK :: Bool
+ test2Message :: String
+ (test2OK, test2Message)
+ | null outdatedStaticallyUsedCodes
+ = (True,) $
+ "- All outdated 'GhcDiagnosticCode' equations are statically unused."
+ | otherwise
+ = (False,) $
+ unlines [ "- The following 'GhcDiagnosticCode' equation" ++ (if plural2 then "s are" else " is") ++ " still in use,"
+ , " even though " ++ (if plural2 then "they are" else "it is") ++ " marked as being outdated."
+ , " Perhaps you should remove the 'Outdated' tag on " ++ (if plural2 then "them" else "it") ++ "."
+ , ""
+ , showDiagnosticCodesWith printOutdatedUsed outdatedStaticallyUsedCodes
+ ]
+ putStrLn test2Message
+ putStrLn ""
+
+ -------------------------
+ -- Code coverage checks.
+
+ -- Test 3: all statically used diagnostic codes are covered by the testsuite,
+ -- (exceptions are allowed in the test output).
+ coveredCodes <- getCoveredCodes
+ when ( null coveredCodes ) $
+ error $ unlines [ "internal error in 'lint-codes' test:"
+ , " failed to parse any diagnostic codes from the testsuite"
+ ]
+
+ let uncoveredCodes :: Map DiagnosticCode (FamEqnIndex, String)
+ uncoveredCodes = (familyEqnUsedCodes `Map.intersection` staticallyUsedCodes)
+ `Map.withoutKeys` coveredCodes
+ plural3 = length uncoveredCodes > 1
+ test3OK :: Bool
+ test3Message :: String
+ (test3OK, test3Message)
+ | null uncoveredCodes
+ = (True,) $
+ "- All diagnostic codes are covered by the testsuite."
+ | otherwise
+ = (False,) $
+ unlines [ "- The following diagnostic code" ++ (if plural3 then "s seem" else " seems") ++ " to not be covered by any tests,"
+ , " as determined by analysing all '.stderr' and '.stdout' files in the testsuite."
+ , " If there is a change in the expected output of this test, you can:"
+ , " - add test cases to exercise any newly uncovered diagnostic codes,"
+ , " - accept the expected output of the 'codes' test by passing the '-a' flag to Hadrian."
+ , ""
+ , showDiagnosticCodesWith printUntested uncoveredCodes
+ ]
+
+ putStrLn test3Message
+ when (test1OK && test2OK && test3OK) do
+ putStrLn ""
+ putStrLn "All good!"
+
+-- | Show a collection of diagnostic codes, ordered by the index in which
+-- the diagnostic code appears in the 'GhcDiagnosticCode' type family.
+showDiagnosticCodesWith :: ( (DiagnosticCode, String) -> String )
+ -- ^ how to print each diagnostic code
+ -> Map DiagnosticCode (FamEqnIndex, String) -> String
+showDiagnosticCodesWith f codes = unlines $ map showCodeCon $ sortOn famEqnIndex $ Map.toList codes
+ where
+ showCodeCon :: (DiagnosticCode, (FamEqnIndex, String)) -> String
+ showCodeCon (code, (_, con)) = f (code, con)
+ famEqnIndex :: (DiagnosticCode, (FamEqnIndex, String)) -> FamEqnIndex
+ famEqnIndex (_, (i,_)) = i
+
+printUnused, printOutdatedUsed, printUntested :: (DiagnosticCode, String) -> String
+printUnused (code, con) =
+ "Unused equation: GhcDiagnosticCode " ++ show con ++ " = " ++ showDiagnosticCodeNumber code
+printOutdatedUsed (code, con) =
+ "Outdated equation is used: GhcDiagnosticCode " ++ show con ++ " = Outdated " ++ showDiagnosticCodeNumber code
+printUntested (code, con) =
+ "[" ++ show code ++ "] is untested (constructor = " ++ con ++ ")"
+
+showDiagnosticCodeNumber :: DiagnosticCode -> String
+showDiagnosticCodeNumber (DiagnosticCode { diagnosticCodeNumber = c })
+ = printf "%05d" c
=====================================
linters/lint-codes/Makefile
=====================================
@@ -0,0 +1,15 @@
+# -----------------------------------------------------------------------------
+#
+# (c) 2009 The University of Glasgow
+#
+# This file is part of the GHC build system.
+#
+# To understand how the build system works and how to modify it, see
+# https://gitlab.haskell.org/ghc/ghc/wikis/building/architecture
+# https://gitlab.haskell.org/ghc/ghc/wikis/building/modifying
+#
+# -----------------------------------------------------------------------------
+
+dir = linters/lint-codes
+TOP = ../..
+include $(TOP)/mk/sub-makefile.mk
=====================================
linters/lint-codes/cabal.project
=====================================
@@ -0,0 +1 @@
+packages: .
=====================================
linters/lint-codes/ghc.mk
=====================================
@@ -0,0 +1,18 @@
+# -----------------------------------------------------------------------------
+#
+# (c) 2009 The University of Glasgow
+#
+# This file is part of the GHC build system.
+#
+# To understand how the build system works and how to modify it, see
+# https://gitlab.haskell.org/ghc/ghc/wikis/building/architecture
+# https://gitlab.haskell.org/ghc/ghc/wikis/building/modifying
+#
+# -----------------------------------------------------------------------------
+
+linters/lint-codes_USES_CABAL = YES
+linters/lint-codes_PACKAGE = lint-codes
+linters/lint-codes_dist-install_PROGNAME = lint-codes
+linters/lint-codes_dist-install_INSTALL = NO
+linters/lint-codes_dist-install_INSTALL_INPLACE = YES
+$(eval $(call build-prog,linters/lint-codes,dist-install,1))
=====================================
linters/lint-codes/lint-codes.cabal
=====================================
@@ -0,0 +1,42 @@
+cabal-version: 2.4
+name: lint-codes
+version: 0.1.0.0
+synopsis: A tool for checking coverage of GHC diagnostic codes
+bug-reports: https://gitlab.haskell.org/ghc/ghc
+license: BSD-3-Clause
+author: Sam Derbyshire
+maintainer: sam at well-typed.com
+copyright: (c) 2023 Sam Derbyshire
+
+executable lint-codes
+
+ main-is:
+ Main.hs
+
+ other-modules:
+ LintCodes.Coverage
+ LintCodes.Static
+
+ build-depends:
+ base >= 4 && < 5
+ , ghc >= 9.9
+ , bytestring
+ , containers
+ , directory
+ , filepath
+ , text
+ , transformers
+ , process
+
+ default-language:
+ Haskell2010
+
+ ghc-options:
+ -O1
+ -Wall
+ -Wcompat
+ -fwarn-missing-local-signatures
+ -fwarn-incomplete-patterns
+ -fwarn-incomplete-uni-patterns
+ -fwarn-missing-deriving-strategies
+ -fno-warn-unticked-promoted-constructors
=====================================
testsuite/mk/boilerplate.mk
=====================================
@@ -239,6 +239,10 @@ ifeq "$(LINT_NOTES)" ""
LINT_NOTES := $(abspath $(TOP)/../inplace/bin/lint-notes)
endif
+ifeq "$(LINT_CODES)" ""
+LINT_CODES:= $(abspath $(TOP)/../inplace/bin/lint-codes)
+endif
+
ifeq "$(LINT_WHITESPACE)" ""
LINT_WHITESPACE := $(abspath $(TOP)/../inplace/bin/lint-whitespace)
endif
=====================================
testsuite/tests/diagnostic-codes/Makefile
=====================================
@@ -0,0 +1,6 @@
+TOP=../..
+
+LIBDIR := "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`"
+
+codes:
+ (cd $(TOP)/.. && $(LINT_CODES) $(LIBDIR))
=====================================
testsuite/tests/diagnostic-codes/all.T
=====================================
@@ -0,0 +1,12 @@
+
+# Copied from linters/all.T:
+def has_ls_files() -> bool:
+ try:
+ files = subprocess.check_output(['git', 'ls-files']).splitlines()
+ return b"hie.yaml" in files
+ except subprocess.CalledProcessError:
+ return False
+
+test('codes', [ normal if has_ls_files() else skip
+ , req_hadrian_deps(["lint:codes"]) ]
+ , makefile_test, ['codes'])
=====================================
testsuite/tests/diagnostic-codes/codes.stdout
=====================================
@@ -0,0 +1,127 @@
+
+- All non-outdated 'GhcDiagnosticCode' equations are statically used.
+
+- All outdated 'GhcDiagnosticCode' equations are statically unused.
+
+- The following diagnostic codes seem to not be covered by any tests,
+ as determined by analysing all '.stderr' and '.stdout' files in the testsuite.
+ If there is a change in the expected output of this test, you can:
+ - add test cases to exercise any newly uncovered diagnostic codes,
+ - accept the expected output of the 'codes' test by passing the '-a' flag to Hadrian.
+
+[GHC-93315] is untested (constructor = DsUselessSpecialiseForClassMethodSelector)
+[GHC-58181] is untested (constructor = DsOrphanRule)
+[GHC-69441] is untested (constructor = DsRuleLhsTooComplicated)
+[GHC-19551] is untested (constructor = DsAggregatedViewExpressions)
+[GHC-75725] is untested (constructor = PsErrCmmLexer)
+[GHC-09848] is untested (constructor = PsErrCmmParser)
+[GHC-95644] is untested (constructor = PsErrBangPatWithoutSpace)
+[GHC-45106] is untested (constructor = PsErrInvalidInfixHole)
+[GHC-44524] is untested (constructor = PsErrExpectedHyphen)
+[GHC-28021] is untested (constructor = PsErrRecordSyntaxInPatSynDecl)
+[GHC-24737] is untested (constructor = PsErrInvalidWhereBindInPatSynDecl)
+[GHC-65536] is untested (constructor = PsErrNoSingleWhereBindInPatSynDecl)
+[GHC-50396] is untested (constructor = PsErrInvalidRuleActivationMarker)
+[GHC-16863] is untested (constructor = PsErrUnsupportedBoxedSumPat)
+[GHC-40845] is untested (constructor = PsErrUnpackDataCon)
+[GHC-08195] is untested (constructor = PsErrInvalidRecordCon)
+[GHC-07636] is untested (constructor = PsErrLambdaCaseInPat)
+[GHC-92971] is untested (constructor = PsErrCaseCmdInFunAppCmd)
+[GHC-47171] is untested (constructor = PsErrLambdaCaseCmdInFunAppCmd)
+[GHC-97005] is untested (constructor = PsErrIfCmdInFunAppCmd)
+[GHC-70526] is untested (constructor = PsErrLetCmdInFunAppCmd)
+[GHC-77808] is untested (constructor = PsErrDoCmdInFunAppCmd)
+[GHC-67630] is untested (constructor = PsErrMDoInFunAppExpr)
+[GHC-25037] is untested (constructor = PsErrCaseInFunAppExpr)
+[GHC-90355] is untested (constructor = PsErrLetInFunAppExpr)
+[GHC-01239] is untested (constructor = PsErrIfInFunAppExpr)
+[GHC-04807] is untested (constructor = PsErrProcInFunAppExpr)
+[GHC-33856] is untested (constructor = PsErrSuffixAT)
+[GHC-25078] is untested (constructor = PsErrPrecedenceOutOfRange)
+[GHC-18910] is untested (constructor = PsErrSemiColonsInCondCmd)
+[GHC-66418] is untested (constructor = PsErrParseErrorOnInput)
+[GHC-85316] is untested (constructor = PsErrMalformedDecl)
+[GHC-49196] is untested (constructor = DriverFileNotFound)
+[GHC-19971] is untested (constructor = DriverBackpackModuleNotFound)
+[GHC-37141] is untested (constructor = DriverCannotLoadInterfaceFile)
+[GHC-29747] is untested (constructor = DriverMissingSafeHaskellMode)
+[GHC-06200] is untested (constructor = BlockedEquality)
+[GHC-81325] is untested (constructor = ExpectingMoreArguments)
+[GHC-78125] is untested (constructor = AmbiguityPreventsSolvingCt)
+[GHC-89223] is untested (constructor = KindMismatch)
+[GHC-84170] is untested (constructor = TcRnModMissingRealSrcSpan)
+[GHC-95822] is untested (constructor = TcRnSimplifierTooManyIterations)
+[GHC-17268] is untested (constructor = TcRnCharLiteralOutOfRange)
+[GHC-36495] is untested (constructor = TcRnTagToEnumMissingValArg)
+[GHC-55868] is untested (constructor = TcRnArrowIfThenElsePredDependsOnResultTy)
+[GHC-51876] is untested (constructor = TcRnDupeModuleExport)
+[GHC-64649] is untested (constructor = TcRnNullExportedModule)
+[GHC-94558] is untested (constructor = TcRnExportHiddenComponents)
+[GHC-63055] is untested (constructor = TcRnFieldUpdateInvalidType)
+[GHC-26133] is untested (constructor = TcRnForeignImportPrimSafeAnn)
+[GHC-03355] is untested (constructor = TcRnIllegalForeignDeclBackend)
+[GHC-01245] is untested (constructor = TcRnUnsupportedCallConv)
+[GHC-01570] is untested (constructor = TcRnExpectedValueId)
+[GHC-96665] is untested (constructor = TcRnMultipleInlinePragmas)
+[GHC-88293] is untested (constructor = TcRnUnexpectedPragmas)
+[GHC-85337] is untested (constructor = TcRnSpecialiseNotVisible)
+[GHC-91382] is untested (constructor = TcRnIllegalKindSignature)
+[GHC-72520] is untested (constructor = TcRnIgnoreSpecialisePragmaOnDefMethod)
+[GHC-10969] is untested (constructor = TcRnTyThingUsedWrong)
+[GHC-61072] is untested (constructor = TcRnGADTDataContext)
+[GHC-16409] is untested (constructor = TcRnMultipleConForNewtype)
+[GHC-54478] is untested (constructor = TcRnRedundantSourceImport)
+[GHC-78448] is untested (constructor = TcRnIllegalDataCon)
+[GHC-44990] is untested (constructor = TcRnGhciMonadLookupFail)
+[GHC-77343] is untested (constructor = TcRnIllegalQuasiQuotes)
+[GHC-22221] is untested (constructor = TyVarRoleMismatch)
+[GHC-99991] is untested (constructor = TyVarMissingInEnv)
+[GHC-92834] is untested (constructor = BadCoercionRole)
+[GHC-93008] is untested (constructor = HsigShapeSortMismatch)
+[GHC-68444] is untested (constructor = SumAltArityExceeded)
+[GHC-63966] is untested (constructor = IllegalSumAlt)
+[GHC-28709] is untested (constructor = MalformedType)
+[GHC-23882] is untested (constructor = IllegalDeclaration)
+[GHC-63930] is untested (constructor = MultiWayIfWithoutAlts)
+[GHC-91745] is untested (constructor = CasesExprWithoutAlts)
+[GHC-60220] is untested (constructor = InvalidCCallImpent)
+[GHC-18816] is untested (constructor = RecGadtNoCons)
+[GHC-38140] is untested (constructor = GadtNoCons)
+[GHC-37056] is untested (constructor = InvalidTypeInstanceHeader)
+[GHC-78486] is untested (constructor = InvalidTyFamInstLHS)
+[GHC-39639] is untested (constructor = DefaultDataInstDecl)
+[GHC-92057] is untested (constructor = ImportLookupAmbiguous)
+[GHC-91901] is untested (constructor = InstHeadMultiParam)
+[GHC-78822] is untested (constructor = AssocDefaultNotAssoc)
+[GHC-43510] is untested (constructor = NotSimpleUnliftedType)
+[GHC-41843] is untested (constructor = IOResultExpected)
+[GHC-07641] is untested (constructor = AtLeastOneArgExpected)
+[GHC-64852] is untested (constructor = BadSourceImport)
+[GHC-58427] is untested (constructor = HomeModError)
+[GHC-94559] is untested (constructor = CouldntFindInFiles)
+[GHC-22211] is untested (constructor = MissingPackageFiles)
+[GHC-88719] is untested (constructor = MissingPackageWayFiles)
+[GHC-83249] is untested (constructor = Can'tFindNameInInterface)
+[GHC-75429] is untested (constructor = CircularImport)
+[GHC-53693] is untested (constructor = HiModuleNameMismatchWarn)
+[GHC-47808] is untested (constructor = ExceptionOccurred)
+[GHC-76329] is untested (constructor = NotInScopeTc)
+[GHC-63388] is untested (constructor = DerivErrNotAClass)
+[GHC-37542] is untested (constructor = DerivErrMustHaveExactlyOneConstructor)
+[GHC-45539] is untested (constructor = DerivErrMustHaveSomeParameters)
+[GHC-10372] is untested (constructor = LookupInstErrNotExact)
+[GHC-10373] is untested (constructor = LookupInstErrFlexiVar)
+[GHC-10374] is untested (constructor = LookupInstErrNotFound)
+[GHC-41242] is untested (constructor = EmptyStmtsGroupInParallelComp)
+[GHC-63610] is untested (constructor = MissingBootDefinition)
+[GHC-52886] is untested (constructor = InvalidTopDecl)
+[GHC-77923] is untested (constructor = NonExactName)
+[GHC-86463] is untested (constructor = AddInvalidCorePlugin)
+[GHC-30384] is untested (constructor = CannotReifyInstance)
+[GHC-79890] is untested (constructor = CannotReifyThingNotInTypeEnv)
+[GHC-65923] is untested (constructor = NoRolesAssociatedWithThing)
+[GHC-75721] is untested (constructor = CannotRepresentType)
+[GHC-17599] is untested (constructor = AddTopDeclsUnexpectedDeclarationSplice)
+[GHC-86934] is untested (constructor = ClassPE)
+
+
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0ef1d8aeaf57ecae402142a2b691109ad78900aa
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0ef1d8aeaf57ecae402142a2b691109ad78900aa
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230808/1b2e1b58/attachment-0001.html>
More information about the ghc-commits
mailing list