Simon Jakobi pushed to branch wip/sjakobi/T16836-implicit-field-strictness at Glasgow Haskell Compiler / GHC
Commits:
-
5aa98496
by Simon Jakobi at 2026-08-20T23:30:18+02:00
18 changed files:
- + changelog.d/implicit-field-strictness-warning
- changelog.d/lazy-field-annotations
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- docs/users_guide/exts/strict.rst
- docs/users_guide/using-warnings.rst
- + testsuite/tests/warnings/should_compile/T16836a.hs
- + testsuite/tests/warnings/should_compile/T16836a.stderr
- + testsuite/tests/warnings/should_compile/T16836b.hs
- + testsuite/tests/warnings/should_compile/T16836c.hs
- + testsuite/tests/warnings/should_compile/T16836c.stderr
- testsuite/tests/warnings/should_compile/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +synopsis: Add `-Wimplicit-field-strictness`
|
|
| 3 | +issues: #16836
|
|
| 4 | +mrs: !16555
|
|
| 5 | + |
|
| 6 | +description: {
|
|
| 7 | + The new opt-in warning :ghc-flag:`-Wimplicit-field-strictness` reports
|
|
| 8 | + data constructor fields that lack an explicit strictness annotation
|
|
| 9 | + (``!`` or ``~``).
|
|
| 10 | +} |
| ... | ... | @@ -11,4 +11,7 @@ description: { |
| 11 | 11 | continues to control the default strictness of unannotated fields.
|
| 12 | 12 | |
| 13 | 13 | See `GHC Proposal #752 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0752-lazy-field-annotations.rst>`_.
|
| 14 | + |
|
| 15 | + Also note the new :ghc-flag:`-Wimplicit-field-strictness` warning, which
|
|
| 16 | + reports fields lacking an explicit annotation.
|
|
| 14 | 17 | } |
| ... | ... | @@ -1142,6 +1142,7 @@ data WarningFlag = |
| 1142 | 1142 | | Opt_WarnUnrecognisedModifiers -- ^ @since 10.0
|
| 1143 | 1143 | | Opt_WarnSemaphoreOpenFailure -- Since 10.0.1
|
| 1144 | 1144 | | Opt_WarnDefaultedCallStack -- ^ @since 10.2
|
| 1145 | + | Opt_WarnImplicitFieldStrictness -- ^ @since 10.2
|
|
| 1145 | 1146 | deriving (Eq, Ord, Show, Enum, Bounded)
|
| 1146 | 1147 | |
| 1147 | 1148 | -- | Return the names of a WarningFlag
|
| ... | ... | @@ -1251,6 +1252,7 @@ warnFlagNames wflag = case wflag of |
| 1251 | 1252 | Opt_WarnTypeEqualityRequiresOperators -> "type-equality-requires-operators" :| []
|
| 1252 | 1253 | Opt_WarnMissingRoleAnnotations -> "missing-role-annotations" :| []
|
| 1253 | 1254 | Opt_WarnImplicitRhsQuantification -> "implicit-rhs-quantification" :| []
|
| 1255 | + Opt_WarnImplicitFieldStrictness -> "implicit-field-strictness" :| []
|
|
| 1254 | 1256 | Opt_WarnIncompleteExportWarnings -> "incomplete-export-warnings" :| []
|
| 1255 | 1257 | Opt_WarnIncompleteRecordSelectors -> "incomplete-record-selectors" :| []
|
| 1256 | 1258 | Opt_WarnBadlyLevelledTypes -> "badly-levelled-types" :| []
|
| ... | ... | @@ -2449,6 +2449,7 @@ wWarningFlagsDeps = [minBound..maxBound] >>= \x -> case x of |
| 2449 | 2449 | Opt_WarnUnrecognisedModifiers -> warnSpec x
|
| 2450 | 2450 | Opt_WarnSemaphoreOpenFailure -> warnSpec x
|
| 2451 | 2451 | Opt_WarnDefaultedCallStack -> warnSpec x
|
| 2452 | + Opt_WarnImplicitFieldStrictness -> warnSpec x
|
|
| 2452 | 2453 | |
| 2453 | 2454 | warningGroupsDeps :: [(Deprecation, FlagSpec WarningGroup)]
|
| 2454 | 2455 | warningGroupsDeps = map mk warningGroups
|
| ... | ... | @@ -1384,6 +1384,21 @@ instance Diagnostic TcRnMessage where |
| 1384 | 1384 | hang (text "Missing role annotation" <> colon)
|
| 1385 | 1385 | 2 (text "type role" <+> ppr name <+> hsep (map ppr roles))
|
| 1386 | 1386 | |
| 1387 | + TcRnImplicitFieldStrictness _name _lazy_anns cons -> mkSimpleDecorated $
|
|
| 1388 | + hang (text "Constructor fields without explicit strictness" <> colon)
|
|
| 1389 | + 2 (vcat (map ppr_con cons))
|
|
| 1390 | + where
|
|
| 1391 | + ppr_con (con, fields) =
|
|
| 1392 | + bullet <+> text "In" <+> quotes (ppr con) <> colon <+> ppr_fields fields
|
|
| 1393 | + ppr_fields fields
|
|
| 1394 | + | let names = concat [ns | ImplicitStrictnessRecField _ ns <- fields]
|
|
| 1395 | + , not (null names)
|
|
| 1396 | + = text "field" <> plural names <+> quotedListWithAnd (map ppr names)
|
|
| 1397 | + | otherwise
|
|
| 1398 | + = let poss = [i | ImplicitStrictnessPosField _ i <- fields]
|
|
| 1399 | + in text "the" <+> unquotedListWith (text "and") (map speakNth poss)
|
|
| 1400 | + <+> text "field" <> plural poss
|
|
| 1401 | + |
|
| 1387 | 1402 | TcRnIllformedTypePattern p
|
| 1388 | 1403 | -> mkSimpleDecorated $
|
| 1389 | 1404 | hang (text "Ill-formed type pattern:") 2 (ppr p)
|
| ... | ... | @@ -2693,6 +2708,8 @@ instance Diagnostic TcRnMessage where |
| 2693 | 2708 | -> ErrorWithoutFlag
|
| 2694 | 2709 | TcRnMissingRoleAnnotation{}
|
| 2695 | 2710 | -> WarningWithFlag Opt_WarnMissingRoleAnnotations
|
| 2711 | + TcRnImplicitFieldStrictness{}
|
|
| 2712 | + -> WarningWithFlag Opt_WarnImplicitFieldStrictness
|
|
| 2696 | 2713 | TcRnIllegalInvisTyVarBndr{}
|
| 2697 | 2714 | -> ErrorWithoutFlag
|
| 2698 | 2715 | TcRnIllegalWildcardTyVarBndr{}
|
| ... | ... | @@ -3428,6 +3445,12 @@ instance Diagnostic TcRnMessage where |
| 3428 | 3445 | -> noHints
|
| 3429 | 3446 | TcRnMissingRoleAnnotation{}
|
| 3430 | 3447 | -> noHints
|
| 3448 | + TcRnImplicitFieldStrictness _ lazy_anns _
|
|
| 3449 | + -> SuggestExplicitFieldStrictness
|
|
| 3450 | + : [ useExtensionInOrderTo
|
|
| 3451 | + (text "to allow" <+> quotes (char '~') <+> text "annotations")
|
|
| 3452 | + LangExt.LazyFieldAnnotations
|
|
| 3453 | + | not lazy_anns ]
|
|
| 3431 | 3454 | TcRnIllegalInvisTyVarBndr{}
|
| 3432 | 3455 | -> [suggestExtension LangExt.TypeAbstractions]
|
| 3433 | 3456 | TcRnIllegalWildcardTyVarBndr{}
|
| ... | ... | @@ -123,6 +123,7 @@ module GHC.Tc.Errors.Types ( |
| 123 | 123 | , TypeSyntax(..)
|
| 124 | 124 | , typeSyntaxExtension
|
| 125 | 125 | , SuggestLinear(..)
|
| 126 | + , ImplicitStrictnessField(..)
|
|
| 126 | 127 | |
| 127 | 128 | -- * Errors for hs-boot and signature files
|
| 128 | 129 | , BadBootDecls(..)
|
| ... | ... | @@ -4235,6 +4236,24 @@ data TcRnMessage where |
| 4235 | 4236 | |
| 4236 | 4237 | -}
|
| 4237 | 4238 | TcRnMissingRoleAnnotation :: Name -> [Role] -> TcRnMessage
|
| 4239 | + |
|
| 4240 | + {-| TcRnImplicitFieldStrictness is a warning that occurs when a data
|
|
| 4241 | + constructor field lacks an explicit strictness annotation (@!@ or @~@)
|
|
| 4242 | + |
|
| 4243 | + Controlled by flags:
|
|
| 4244 | + - Wimplicit-field-strictness
|
|
| 4245 | + |
|
| 4246 | + Test cases:
|
|
| 4247 | + T16836a, T16836b
|
|
| 4248 | + |
|
| 4249 | + -}
|
|
| 4250 | + TcRnImplicitFieldStrictness
|
|
| 4251 | + :: Name -- ^ the type constructor
|
|
| 4252 | + -> Bool -- ^ whether @LazyFieldAnnotations@ is enabled
|
|
| 4253 | + -> [(Name, [ImplicitStrictnessField])]
|
|
| 4254 | + -- ^ per data constructor, the fields lacking annotations
|
|
| 4255 | + -> TcRnMessage
|
|
| 4256 | + |
|
| 4238 | 4257 | {-| TcRnPatersonCondFailure is an error that occurs when an instance
|
| 4239 | 4258 | declaration fails to conform to the Paterson conditions. Which particular condition
|
| 4240 | 4259 | fails depends on the constructor of PatersonCondFailure
|
| ... | ... | @@ -6399,6 +6418,14 @@ data PatSynInvalidRhsReason |
| 6399 | 6418 | | PatSynUnboundVar !Name
|
| 6400 | 6419 | deriving (Generic)
|
| 6401 | 6420 | |
| 6421 | +-- | A constructor field lacking an explicit strictness annotation, as
|
|
| 6422 | +-- reported by 'TcRnImplicitFieldStrictness'.
|
|
| 6423 | +data ImplicitStrictnessField
|
|
| 6424 | + = -- | A record field group @x, y :: ty@ sharing one (absent) annotation
|
|
| 6425 | + ImplicitStrictnessRecField SrcSpan [RdrName]
|
|
| 6426 | + | -- | A positional argument (1-based index)
|
|
| 6427 | + ImplicitStrictnessPosField SrcSpan Int
|
|
| 6428 | + |
|
| 6402 | 6429 | data BadFieldAnnotationReason where
|
| 6403 | 6430 | {-| A lazy data type field annotation (~) was used without enabling the
|
| 6404 | 6431 | extension LazyFieldAnnotations.
|
| ... | ... | @@ -4023,8 +4023,39 @@ dataDeclChecks tc_name mctxt cons |
| 4023 | 4023 | ; is_boot <- tcIsHsBootOrSig -- Are we compiling an hs-boot file?
|
| 4024 | 4024 | ; unless (not (null cons) || empty_data_decls || is_boot) $
|
| 4025 | 4025 | addErrTc (TcRnEmptyDataDeclsDisabled tc_name)
|
| 4026 | + |
|
| 4027 | + ; warn_implicit_strictness <- woptM Opt_WarnImplicitFieldStrictness
|
|
| 4028 | + ; when warn_implicit_strictness $ case cons of
|
|
| 4029 | + DataTypeCons False data_cons
|
|
| 4030 | + | let offenders = concatMap conImplicitStrictnessFields data_cons
|
|
| 4031 | + , not (null offenders)
|
|
| 4032 | + -> do { lazy_anns <- xoptM LangExt.LazyFieldAnnotations
|
|
| 4033 | + ; setSrcSpan (getSrcSpan tc_name) $ addDiagnosticTc $
|
|
| 4034 | + TcRnImplicitFieldStrictness tc_name lazy_anns offenders }
|
|
| 4035 | + _ -> return ()
|
|
| 4036 | + |
|
| 4026 | 4037 | ; return gadt_syntax }
|
| 4027 | 4038 | |
| 4039 | +conImplicitStrictnessFields :: LConDecl GhcRn -> [(Name, [ImplicitStrictnessField])]
|
|
| 4040 | +conImplicitStrictnessFields (L _ con)
|
|
| 4041 | + | null fields = []
|
|
| 4042 | + | otherwise = [ (unLoc n, fields) | n <- getConNames con ]
|
|
| 4043 | + where
|
|
| 4044 | + fields = case con of
|
|
| 4045 | + ConDeclH98 { con_args = PrefixCon _ args } -> pos_fields args
|
|
| 4046 | + ConDeclH98 { con_args = InfixCon _ a1 a2 } -> pos_fields [a1, a2]
|
|
| 4047 | + ConDeclH98 { con_args = RecCon _ (L _ flds) } -> rec_fields flds
|
|
| 4048 | + ConDeclGADT { con_g_args = PrefixConGADT _ args } -> pos_fields args
|
|
| 4049 | + ConDeclGADT { con_g_args = RecConGADT _ (L _ flds) } -> rec_fields flds
|
|
| 4050 | + |
|
| 4051 | + pos_fields args = [ ImplicitStrictnessPosField (getLocA (cdf_type f)) i
|
|
| 4052 | + | (i, f) <- zip [1 :: Int ..] args
|
|
| 4053 | + , NoSrcStrict <- [cdf_bang f] ]
|
|
| 4054 | + rec_fields flds = [ ImplicitStrictnessRecField (getLocA (cdf_type spec))
|
|
| 4055 | + [ rdr | L _ (FieldOcc rdr _) <- names ]
|
|
| 4056 | + | L _ (HsConDeclRecField _ names spec) <- flds
|
|
| 4057 | + , NoSrcStrict <- [cdf_bang spec] ]
|
|
| 4058 | + |
|
| 4028 | 4059 | |
| 4029 | 4060 | -----------------------------------
|
| 4030 | 4061 | data DataDeclInfo
|
| ... | ... | @@ -542,6 +542,7 @@ type family GhcDiagnosticCode c = n | n -> c where |
| 542 | 542 | GhcDiagnosticCode "TcRnNegativeNumTypeLiteral" = 93632
|
| 543 | 543 | GhcDiagnosticCode "TcRnUnusedQuantifiedTypeVar" = 54180
|
| 544 | 544 | GhcDiagnosticCode "TcRnMissingRoleAnnotation" = 65490
|
| 545 | + GhcDiagnosticCode "TcRnImplicitFieldStrictness" = 47032
|
|
| 545 | 546 | |
| 546 | 547 | GhcDiagnosticCode "TcRnUntickedPromotedThing" = 49957
|
| 547 | 548 | GhcDiagnosticCode "TcRnIllegalBuiltinSyntax" = 39716
|
| ... | ... | @@ -343,6 +343,14 @@ data GhcHint |
| 343 | 343 | -}
|
| 344 | 344 | | SuggestAddStandaloneKindSignature Name
|
| 345 | 345 | |
| 346 | + {-| Suggests to annotate each constructor field with explicit strictness
|
|
| 347 | + (@!@ or @~@), without picking one.
|
|
| 348 | + |
|
| 349 | + Triggered by: 'GHC.Tc.Errors.Types.TcRnImplicitFieldStrictness'
|
|
| 350 | + Test case(s): warnings/should_compile/T16836a
|
|
| 351 | + -}
|
|
| 352 | + | SuggestExplicitFieldStrictness
|
|
| 353 | + |
|
| 346 | 354 | {-| Suggests the user to fill in the wildcard constraint to
|
| 347 | 355 | disambiguate which constraint that is.
|
| 348 | 356 |
| ... | ... | @@ -185,6 +185,9 @@ instance Outputable GhcHint where |
| 185 | 185 | -> text "Use a standalone deriving declaration instead"
|
| 186 | 186 | SuggestAddStandaloneKindSignature name
|
| 187 | 187 | -> text "Add a standalone kind signature for" <+> quotes (ppr name)
|
| 188 | + SuggestExplicitFieldStrictness
|
|
| 189 | + -> text "Annotate each field with" <+> quotes (char '!')
|
|
| 190 | + <+> text "(strict) or" <+> quotes (char '~') <+> text "(lazy)"
|
|
| 188 | 191 | SuggestFillInWildcardConstraint
|
| 189 | 192 | -> text "Fill in the wildcard constraint yourself"
|
| 190 | 193 | SuggestAppropriateTHTick ns
|
| ... | ... | @@ -194,6 +194,9 @@ The ``~`` annotation must be written in prefix form:: |
| 194 | 194 | See `GHC Proposal #229 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-whitespace-bang-patterns.rst>`__
|
| 195 | 195 | for the precise rules.
|
| 196 | 196 | |
| 197 | +See also :ghc-flag:`-Wimplicit-field-strictness`, which warns about
|
|
| 198 | +fields lacking an explicit annotation.
|
|
| 199 | + |
|
| 197 | 200 | .. _strict-data:
|
| 198 | 201 | |
| 199 | 202 | Strict-by-default data types
|
| ... | ... | @@ -2505,6 +2505,23 @@ of ``-W(no-)*``. |
| 2505 | 2505 | In other words the type-class role cannot be accidentally left
|
| 2506 | 2506 | representational or phantom, which could affected the code correctness.
|
| 2507 | 2507 | |
| 2508 | +.. ghc-flag:: -Wimplicit-field-strictness
|
|
| 2509 | + :shortdesc: warn when constructor fields lack explicit strictness annotations
|
|
| 2510 | + :type: dynamic
|
|
| 2511 | + :reverse: -Wno-implicit-field-strictness
|
|
| 2512 | + :category:
|
|
| 2513 | + |
|
| 2514 | + :since: 10.2.1
|
|
| 2515 | + :default: off
|
|
| 2516 | + |
|
| 2517 | + .. index::
|
|
| 2518 | + single: strictness annotations, missing
|
|
| 2519 | + |
|
| 2520 | + If you would like GHC to check that every data constructor field carries
|
|
| 2521 | + an explicit strictness annotation — ``!`` (strict) or ``~`` (lazy) — use
|
|
| 2522 | + the :ghc-flag:`-Wimplicit-field-strictness` option. It reports one warning
|
|
| 2523 | + per data declaration, listing the unannotated fields of each constructor.
|
|
| 2524 | + |
|
| 2508 | 2525 | .. ghc-flag:: -Wimplicit-rhs-quantification
|
| 2509 | 2526 | :shortdesc: warn when type variables on the RHS of a type synonym are implicitly quantified
|
| 2510 | 2527 | :type: dynamic
|
| 1 | +{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
|
|
| 2 | +{-# LANGUAGE GADTs #-}
|
|
| 3 | +{-# LANGUAGE TypeFamilies #-}
|
|
| 4 | +{-# LANGUAGE TypeOperators #-}
|
|
| 5 | +module T16836a where
|
|
| 6 | + |
|
| 7 | +-- plain multi-constructor data
|
|
| 8 | +-- warns for both constructors
|
|
| 9 | +data T a = MkT a Bool
|
|
| 10 | + | MkT2 !Int a
|
|
| 11 | + |
|
| 12 | +-- record with a shared field group
|
|
| 13 | +-- warns for x, y and z; not for b
|
|
| 14 | +data R = MkR { x, y :: Int, z :: Char, b :: !Bool }
|
|
| 15 | + |
|
| 16 | +-- infix constructor
|
|
| 17 | +-- warns for the first argument
|
|
| 18 | +data I = Int :+: !Bool
|
|
| 19 | + |
|
| 20 | +-- GADT syntax
|
|
| 21 | +-- warns for the first argument
|
|
| 22 | +data G a where
|
|
| 23 | + MkG :: Int -> !Bool -> G a
|
|
| 24 | + |
|
| 25 | +-- GADT record syntax
|
|
| 26 | +-- warns for gx
|
|
| 27 | +data GR a where
|
|
| 28 | + MkGR :: { gx :: Int, gy :: !Bool } -> GR a
|
|
| 29 | + |
|
| 30 | +-- data family instance
|
|
| 31 | +-- warns
|
|
| 32 | +data family F a
|
|
| 33 | +data instance F Int = MkF Char
|
|
| 34 | + |
|
| 35 | +-- fully annotated
|
|
| 36 | +-- doesn't warn
|
|
| 37 | +data S = MkS !Int !Bool |
| 1 | +T16836a.hs:9:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 2 | + • Constructor fields without explicit strictness:
|
|
| 3 | + • In ‘MkT’: the first and second fields
|
|
| 4 | + • In ‘MkT2’: the second field
|
|
| 5 | + • In the data type declaration for ‘T’
|
|
| 6 | + Suggested fixes:
|
|
| 7 | + • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 8 | + • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
|
|
| 9 | + to allow ‘~’ annotations
|
|
| 10 | + |
|
| 11 | +T16836a.hs:14:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 12 | + • Constructor fields without explicit strictness:
|
|
| 13 | + • In ‘MkR’: fields ‘x’, ‘y’ and ‘z’
|
|
| 14 | + • In the data type declaration for ‘R’
|
|
| 15 | + Suggested fixes:
|
|
| 16 | + • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 17 | + • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
|
|
| 18 | + to allow ‘~’ annotations
|
|
| 19 | + |
|
| 20 | +T16836a.hs:18:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 21 | + • Constructor fields without explicit strictness:
|
|
| 22 | + • In ‘:+:’: the first field
|
|
| 23 | + • In the data type declaration for ‘I’
|
|
| 24 | + Suggested fixes:
|
|
| 25 | + • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 26 | + • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
|
|
| 27 | + to allow ‘~’ annotations
|
|
| 28 | + |
|
| 29 | +T16836a.hs:22:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 30 | + • Constructor fields without explicit strictness:
|
|
| 31 | + • In ‘MkG’: the first field
|
|
| 32 | + • In the data type declaration for ‘G’
|
|
| 33 | + Suggested fixes:
|
|
| 34 | + • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 35 | + • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
|
|
| 36 | + to allow ‘~’ annotations
|
|
| 37 | + |
|
| 38 | +T16836a.hs:27:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 39 | + • Constructor fields without explicit strictness:
|
|
| 40 | + • In ‘MkGR’: field ‘gx’
|
|
| 41 | + • In the data type declaration for ‘GR’
|
|
| 42 | + Suggested fixes:
|
|
| 43 | + • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 44 | + • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
|
|
| 45 | + to allow ‘~’ annotations
|
|
| 46 | + |
|
| 47 | +T16836a.hs:32:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 48 | + • Constructor fields without explicit strictness:
|
|
| 49 | + • In ‘MkF’: the first field
|
|
| 50 | + • In the data family instance declaration for ‘F’
|
|
| 51 | + Suggested fixes:
|
|
| 52 | + • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 53 | + • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
|
|
| 54 | + to allow ‘~’ annotations
|
|
| 55 | + |
| 1 | +{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
|
|
| 2 | +{-# LANGUAGE GADTs #-}
|
|
| 3 | +{-# LANGUAGE TypeFamilies #-}
|
|
| 4 | +{-# LANGUAGE TypeData #-}
|
|
| 5 | +{-# LANGUAGE EmptyDataDecls #-}
|
|
| 6 | +{-# LANGUAGE LazyFieldAnnotations #-}
|
|
| 7 | +module T16836b where
|
|
| 8 | + |
|
| 9 | +-- fully annotated declarations don't warn
|
|
| 10 | +data T a = MkT ~a !Bool
|
|
| 11 | +data R = MkR { x, y :: !Int, z :: ~Char }
|
|
| 12 | +data G a where
|
|
| 13 | + MkG :: !Int -> ~Bool -> G a
|
|
| 14 | +data family F a
|
|
| 15 | +data instance F Int = MkF !Char
|
|
| 16 | + |
|
| 17 | +-- newtypes can't have annotations; exempt
|
|
| 18 | +newtype N = MkN Int
|
|
| 19 | + |
|
| 20 | +-- 'type data' can't have annotations; exempt
|
|
| 21 | +type data TD = MkTD Bool
|
|
| 22 | + |
|
| 23 | +-- no fields, nothing to annotate
|
|
| 24 | +data E
|
|
| 25 | +data Nullary = A | B |
| 1 | +{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
|
|
| 2 | +{-# LANGUAGE StrictData #-}
|
|
| 3 | +module T16836c where
|
|
| 4 | + |
|
| 5 | +-- unannotated fields warn under StrictData too
|
|
| 6 | +data T a = MkT a !Bool ~Char |
| 1 | +T16836c.hs:6:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
|
|
| 2 | + • Constructor fields without explicit strictness:
|
|
| 3 | + • In ‘MkT’: the first field
|
|
| 4 | + • In the data type declaration for ‘T’
|
|
| 5 | + Suggested fix: Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
|
|
| 6 | + |
| ... | ... | @@ -91,3 +91,6 @@ test('T25901_imp_unused_3', [extra_files(['T25901_helper_3.hs'])], multimod_comp |
| 91 | 91 | test('T25901_imp_unused_4', normal, compile, ['-Wunused-imports'])
|
| 92 | 92 | test('T25901_imp_dodgy_1', [extra_files(['T25901_helper_1.hs'])], multimod_compile, ['T25901_imp_dodgy_1', '-v0 -Wdodgy-imports'])
|
| 93 | 93 | test('T25901_imp_dodgy_2', [extra_files(['T25901_helper_2.hs'])], multimod_compile, ['T25901_imp_dodgy_2', '-v0 -Wdodgy-imports'])
|
| 94 | +test('T16836a', normal, compile, [''])
|
|
| 95 | +test('T16836b', normal, compile, [''])
|
|
| 96 | +test('T16836c', normal, compile, ['']) |