[Git][ghc/ghc][wip/rafl/hpc-instances] 9 commits: hpc: WIP test
by Florian Ragwitz (@rafl) 04 Sep '26
by Florian Ragwitz (@rafl) 04 Sep '26
04 Sep '26
Florian Ragwitz pushed to branch wip/rafl/hpc-instances at Glasgow Haskell Compiler / GHC
Commits:
f2d8165d by Florian Ragwitz at 2026-09-03T13:18:32-07:00
hpc: WIP test
- - - - -
b59bce58 by Florian Ragwitz at 2026-09-03T13:18:32-07:00
hpc: Make instances available in TickTransEnv
- - - - -
3bce9b7d by Florian Ragwitz at 2026-09-03T13:18:32-07:00
hpc: Capture which method Ids belong to which dictionary function Id
- - - - -
7449851e by Florian Ragwitz at 2026-09-03T13:18:32-07:00
hpc: Carry method id mapping in TcGblEnv
- - - - -
87b43c0e by Florian Ragwitz at 2026-09-03T13:18:32-07:00
hpc: pass instance method mapping to addTicksToBinds and propagate ABEs
- - - - -
304ac851 by Florian Ragwitz at 2026-09-03T13:18:32-07:00
hpc: Do not create top-level boxes for generated instance methods
Users care about which of their written methods are or aren't covered, not
whether all of the inherited methods are covered as well. Those should be
covered where they are implemented.
This set of changes achieves the above by stopping to generate top-level boxes
which will often appear as uncovered with no clear indication as to why, and no
way to fix other than excercising code the user has not written.
- - - - -
4da0c157 by Florian Ragwitz at 2026-09-03T19:36:04-07:00
hpc: Allocate one top-level box for each class instance for coverage
- - - - -
ef171e23 by Florian Ragwitz at 2026-09-03T19:59:16-07:00
hpc: Tick top-level boxes for instances when any method is used at run-time
- - - - -
46aeba43 by Florian Ragwitz at 2026-09-03T20:05:20-07:00
hpc: Don't allocate boxes for methodless classes
With the plumbing we currently have, these could never be covered, which is not
helpful to hpc users. This could be improved upon further.
- - - - -
9 changed files:
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Utils/Monad.hs
- + testsuite/tests/hpc/instmeths/instmeths.hs
- + testsuite/tests/hpc/instmeths/instmeths.stdout
- + testsuite/tests/hpc/instmeths/test.T
Changes:
=====================================
compiler/GHC/HsToCore.hs
=====================================
@@ -147,6 +147,7 @@ deSugar hsc_env
tcg_tcs = tcs,
tcg_default_exports = defaults,
tcg_insts = insts,
+ tcg_inst_meths = inst_meths,
tcg_fam_insts = fam_insts,
tcg_complete_matches = complete_matches,
tcg_self_boot = self_boot
@@ -170,7 +171,8 @@ deSugar hsc_env
(hsc_logger hsc_env)
(initTicksConfig (hsc_dflags hsc_env))
mod mod_loc
- export_set (typeEnvTyCons type_env) binds
+ export_set (typeEnvTyCons type_env)
+ insts inst_meths binds
else return (binds, Nothing)
; let modBreaks
| Just (_, _, breakpointSpecs) <- m_tickInfo
=====================================
compiler/GHC/HsToCore/Ticks.hs
=====================================
@@ -24,6 +24,8 @@ import GHC.Unit
import GHC.Core.Type
import GHC.Core.TyCon
+import GHC.Core.InstEnv
+import GHC.Core.Class
import GHC.Data.Maybe
import GHC.Data.FastString
@@ -100,11 +102,13 @@ addTicksToBinds
-- isExportedId doesn't work yet (the desugarer
-- hasn't set it), so we have to work from this set.
-> [TyCon] -- ^ Type constructors in this module
+ -> [ClsInst]
+ -> IdEnv DFunId
-> LHsBinds GhcTc
-> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick, SizedSeq Tick))
addTicksToBinds logger cfg
- mod mod_loc exports tyCons binds
+ mod mod_loc exports tyCons insts inst_meths binds
| let passes = ticks_passes cfg
, not (null passes)
, Just orig_file <- ml_hs_file mod_loc = do
@@ -129,8 +133,13 @@ addTicksToBinds logger cfg
, this_mod = mod
, tickishType = tickish
, recSelBinds = emptyVarEnv
+ , instMeths = inst_meths
+ , instTicks = emptyVarEnv
}
- (binds',_,st') = unTM (addTickLHsBinds binds) env st
+ addTick = do
+ instTicks <- allocInstTicks insts
+ withEnv (\e -> e{ instTicks }) $ addTickLHsBinds binds
+ (binds',_,st') = unTM addTick env st
in (binds', st')
(binds1,st) = foldr tickPass (binds, initTTState) passes
@@ -231,7 +240,7 @@ addTickLHsBind :: LHsBind GhcTc -> TM (LHsBind GhcTc)
addTickLHsBind (L pos (XHsBindsLR bind@(AbsBinds { abs_binds = binds
, abs_exports = abs_exports
}))) =
- withEnv (add_rec_sels . add_inlines . add_exports) $ do
+ withEnv (add_inst_meths . add_rec_sels . add_inlines . add_exports) $ do
binds' <- addTickLHsBinds binds
return $ L pos $ XHsBindsLR $ bind { abs_binds = binds' }
where
@@ -259,19 +268,26 @@ addTickLHsBind (L pos (XHsBindsLR bind@(AbsBinds { abs_binds = binds
| ABE{ abe_poly, abe_mono } <- abs_exports
, RecSelId{} <- [idDetails abe_poly] ] }
+ add_inst_meths env =
+ env{ instMeths = instMeths env `extendVarEnvList`
+ [ (abe_mono, dfun)
+ | ABE{ abe_poly, abe_mono } <- abs_exports
+ , Just dfun <- [lookupVarEnv (instMeths env) abe_poly] ] }
+
addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches }))) = do
let name = getOccString id
decl_path <- getPathEntry
density <- getDensity
+ env <- getEnv
- inline_ids <- liftM inlines getEnv
-- See Note [inline sccs]
let inline = isInlinePragma (idInlinePragma id)
- || id `elemVarSet` inline_ids
+ || id `elemVarSet` inlines env
-- See Note [inline sccs]
- tickish <- tickishType `liftM` getEnv
- case tickish of { ProfNotes | inline -> return (L pos funBind); _ -> do
+ case tickishType env of { ProfNotes | inline -> return (L pos funBind); _ -> do
+
+ instTick <- instMethTick id
-- See Note [Record-selector ticks]
selTicks <- recSelTick id
@@ -294,8 +310,12 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches
toplev = null decl_path
exported = idName id `elemNameSet` exported_names
- tick <- if not blackListed &&
- shouldTickBind density toplev exported simple inline
+ let generatedInstMeth = id `elemVarEnv` instMeths env
+ && isGenerated (mg_origin (mg_ext matches))
+
+ tick <- if not generatedInstMeth
+ && not blackListed
+ && shouldTickBind density toplev exported simple inline
then
bindTick density name (locA pos) fvs
else
@@ -303,7 +323,8 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches
let mbCons = maybe Prelude.id (:)
return $ L pos $ funBind { fun_matches = mg
- , fun_ext = second (tick `mbCons`) (fun_ext funBind) }
+ , fun_ext = second ((instTick `mbCons`) . (tick `mbCons`))
+ (fun_ext funBind) }
} }
where
-- See Note [Record-selector ticks]
@@ -1098,6 +1119,8 @@ data TickTransEnv = TTE { fileName :: FastString
, this_mod :: Module
, tickishType :: TickishType
, recSelBinds :: IdEnv DVarSet
+ , instMeths :: IdEnv DFunId
+ , instTicks :: IdEnv CoreTickish
}
-- deriving Show
@@ -1238,6 +1261,21 @@ isBlackListed (RealSrcSpan pos _) = TM $ \ env st -> (Set.member pos (blackList
isBlackListed GeneratedSrcSpan{} = return False
isBlackListed UnhelpfulSpan{} = return False
+allocInstTicks :: [ClsInst] -> TM (IdEnv CoreTickish)
+allocInstTicks insts =
+ ifDensity TickForCoverage (mkVarEnv . catMaybes <$> mapM alloc insts) (pure emptyVarEnv)
+ where
+ alloc inst
+ | null (classMethods (is_cls inst)) = pure Nothing
+ | otherwise = do
+ let dfun = is_dfun inst
+ fmap (dfun,) <$> allocATickBox (TopLevelBox [getOccString dfun])
+ False True (getSrcSpan dfun) noFVs
+
+instMethTick :: Id -> TM (Maybe CoreTickish)
+instMethTick id = getEnv >>= \e ->
+ pure $ lookupVarEnv (instMeths e) id >>= lookupVarEnv (instTicks e)
+
-- the tick application inherits the source position of its
-- expression argument to support nested box allocations
allocTickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> TM (HsExpr GhcTc)
=====================================
compiler/GHC/Tc/Module.hs
=====================================
@@ -1770,7 +1770,7 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
-- Second pass over class and instance declarations,
-- now using the kind-checked decls
traceTc "Tc6" empty ;
- inst_binds <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;
+ (inst_binds, inst_meths) <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;
-- Foreign exports
traceTc "Tc7" empty ;
@@ -1802,8 +1802,9 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
, tcg_anns = tcg_anns tcg_env ++ annotations
, tcg_ann_env = extendAnnEnvList (tcg_ann_env tcg_env) annotations
, tcg_fords = tcg_fords tcg_env ++ foe_decls ++ fi_decls
- , tcg_dus = tcg_dus tcg_env `plusDU` usesOnly fo_fvs } } ;
+ , tcg_dus = tcg_dus tcg_env `plusDU` usesOnly fo_fvs
-- tcg_dus: see Note [Newtype constructor usage in foreign declarations]
+ , tcg_inst_meths = tcg_inst_meths tcg_env `plusVarEnv` inst_meths } } ;
-- See Note [Newtype constructor usage in foreign declarations]
addUsedGREs NoDeprecationWarnings (bagToList fo_gres) ;
=====================================
compiler/GHC/Tc/TyCl/Instance.hs
=====================================
@@ -1282,7 +1282,7 @@ takes a slightly different approach.
********************************************************************* -}
tcInstDecls2 :: [LTyClDecl GhcRn] -> [InstInfo GhcRn]
- -> TcM (LHsBinds GhcTc)
+ -> TcM (LHsBinds GhcTc, IdEnv DFunId)
-- (a) From each class declaration,
-- generate any default-method bindings
-- (b) From each instance decl
@@ -1299,11 +1299,11 @@ tcInstDecls2 tycl_decls inst_decls
-- Add the default method Ids (again)
-- (they were already added in GHC.Tc.TyCl.Utils.tcAddImplicits)
-- See Note [Default methods in the type environment]
- ; inst_binds_s <- tcExtendGlobalValEnv dm_ids $
- mapM tcInstDecl2 inst_decls
+ ; (inst_binds_s, inst_meths_s) <- unzip <$> (tcExtendGlobalValEnv dm_ids $
+ mapM tcInstDecl2 inst_decls)
-- Done
- ; return (dm_binds ++ concat inst_binds_s) }
+ ; return (dm_binds ++ concat inst_binds_s, plusVarEnvList inst_meths_s) }
{- Note [Default methods in the type environment]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1319,12 +1319,12 @@ So right here in tcInstDecls2 we must re-extend the type envt with
the default method Ids replete with their INLINE pragmas. Urk.
-}
-tcInstDecl2 :: InstInfo GhcRn -> TcM (LHsBinds GhcTc)
+tcInstDecl2 :: InstInfo GhcRn -> TcM (LHsBinds GhcTc, IdEnv DFunId)
-- Returns a binding for the dfun
tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
- = recoverM (return emptyLHsBinds) $
- setSrcSpan loc $
- addErrCtxt (instDeclCtxt2 dfun_ty) $
+ = recoverM (return (emptyLHsBinds, emptyVarEnv)) $
+ setSrcSpan loc $
+ addErrCtxt (instDeclCtxt2 dfun_ty) $
do { -- Instantiate the instance decl with skolem constants
(skol_info, inst_tyvars, dfun_theta, clas, inst_tys) <- tcSkolDFunType dfun_ty
; dfun_ev_vars <- newEvVars dfun_theta
@@ -1342,7 +1342,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
-- See Note [Typechecking plan for instance declarations]
; dfun_ev_binds_var <- newTcEvBinds
; let dfun_ev_binds = TcEvBinds dfun_ev_binds_var
- ; (tclvl, (sc_meth_ids, sc_meth_binds, sc_meth_implics))
+ ; (tclvl, (sc_meth_ids, sc_meth_binds, sc_meth_implics, meth_ids))
<- pushTcLevelM $
do { (sc_ids, sc_binds, sc_implics)
<- tcSuperClasses skol_info dfun_id clas inst_tyvars
@@ -1356,7 +1356,8 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
; return ( sc_ids ++ meth_ids
, sc_binds ++ meth_binds
- , sc_implics `unionBags` meth_implics ) }
+ , sc_implics `unionBags` meth_implics
+ , meth_ids ) }
; imp <- newImplication
; emitImplication $
@@ -1413,7 +1414,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
, abs_binds = [dict_bind]
, abs_sig = True }
- ; return (L loc' main_bind : sc_meth_binds)
+ ; return (L loc' main_bind : sc_meth_binds, mkVarEnv $ (,dfun_id) <$> meth_ids)
}
where
dfun_id = instanceDFunId ispec
=====================================
compiler/GHC/Tc/Types.hs
=====================================
@@ -157,6 +157,7 @@ import GHC.Types.Name.Env
import GHC.Types.Name.Set
import GHC.Types.Avail
import GHC.Types.Var
+import GHC.Types.Var.Env
import GHC.Types.TypeEnv
import GHC.Types.SourceFile
import GHC.Types.SrcLoc
@@ -528,6 +529,7 @@ data TcGblEnv
-- ^ Instance envt for all /home-package/ modules;
-- Includes the dfuns in tcg_insts
-- NB. BangPattern is to fix a leak, see #15111
+ tcg_inst_meths :: IdEnv DFunId,
tcg_fam_inst_env :: !FamInstEnv, -- ^ Ditto for family instances
-- NB. BangPattern is to fix a leak, see #15111
tcg_ann_env :: AnnEnv, -- ^ And for annotations
=====================================
compiler/GHC/Tc/Utils/Monad.hs
=====================================
@@ -409,6 +409,7 @@ initTcGblEnv hsc_env hsc_src keep_rn_syntax mod loc =
, tcg_knot_vars = hsc_type_env_vars hsc_env
, tcg_known_key_maps = known_key_maps_var
, tcg_inst_env = emptyInstEnv
+ , tcg_inst_meths = emptyVarEnv
, tcg_fam_inst_env = emptyFamInstEnv
, tcg_ann_env = emptyAnnEnv
, tcg_complete_match_env = []
=====================================
testsuite/tests/hpc/instmeths/instmeths.hs
=====================================
@@ -0,0 +1,47 @@
+import Data.Bifunctor
+import Data.List
+import Data.Maybe
+
+import Trace.Hpc.Mix
+import Trace.Hpc.Reflect
+import Trace.Hpc.Tix
+import Trace.Hpc.Util (HpcPos, fromHpcPos, readFileUtf8)
+
+data T = T
+
+class Foo a where
+ inheritedMethod :: a -> Int
+ inheritedMethod _ = 23
+
+ explicitMethod :: a -> Int
+
+instance Foo T where
+ explicitMethod _ = 42
+
+interesting :: (Int, MixEntry) -> Maybe (Int, HpcPos, [String])
+interesting (n, (pos, TopLevelBox path))
+ | any isInteresting path = Just (n, pos, path)
+ where
+ isInteresting name =
+ "inheritedMethod" `isInfixOf` name
+ || "explicitMethod" `isInfixOf` name
+interesting _ = Nothing
+
+sourceAt :: String -> HpcPos -> String
+sourceAt src pos
+ | l1 == l2 = take (c2 - c1 + 1) . drop (c1 - 1) $ ls !! (l1 - 1)
+ | otherwise = intercalate "\n" $ first : (middle ++ [last])
+ where
+ (l1, c1, l2, c2) = fromHpcPos pos
+ ls = lines src
+ first = drop (c1 - 1) $ ls !! (l1 - 1)
+ middle = take (l2 - l1 - 1) $ drop l1 ls
+ last = take c2 $ ls !! (l2 - 1)
+
+main :: IO ()
+main = do
+ Mix source _ _ _ mixEntries <- readMix [".hpc"] (Left "Main")
+ src <- readFileUtf8 source
+ let boxes = mapMaybe interesting $ zip [0 ..] mixEntries
+ Tix [TixModule "Main" _ _ counts] <- examineTix
+ mapM_ print [ (counts !! n, path, sourceAt src pos) | (n, pos, path) <- boxes ]
=====================================
testsuite/tests/hpc/instmeths/instmeths.stdout
=====================================
=====================================
testsuite/tests/hpc/instmeths/test.T
=====================================
@@ -0,0 +1,5 @@
+setTestOpts([omit_ghci, when(fast(), skip), js_skip])
+
+test('instmeths',
+ [ignore_extension],
+ compile_and_run, ['-fhpc'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/afe5fe8057f9a48af9adcceee7fb48…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/afe5fe8057f9a48af9adcceee7fb48…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/az/exactprint-annotation-rationalisation] 11 commits: EPA: Located do statements
by Alan Zimmerman (@alanz) 04 Sep '26
by Alan Zimmerman (@alanz) 04 Sep '26
04 Sep '26
Alan Zimmerman pushed to branch wip/az/exactprint-annotation-rationalisation at Glasgow Haskell Compiler / GHC
Commits:
ddaa9dad by Alan Zimmerman at 2026-09-03T21:14:34+01:00
EPA: Located do statements
- - - - -
d1903a7d by Alan Zimmerman at 2026-09-03T22:19:43+01:00
EPA: Print RecStmt located
- - - - -
b2b6f17a by Alan Zimmerman at 2026-09-03T22:55:11+01:00
EPA: HsCmdDo Located
- - - - -
f48723a3 by Alan Zimmerman at 2026-09-03T22:59:45+01:00
Extend Test20297 for additional occurrences
- - - - -
7819a32e by Alan Zimmerman at 2026-09-03T22:59:45+01:00
Plan update DO NOT COMMIT
- - - - -
9571a5ba by Alan Zimmerman at 2026-09-03T22:59:45+01:00
EPA: First pass implementation of HsList, for ClassDecls
Just as a straight list replacement to start with, no payload.
This shows the scope and invasiveness of the initial change
- - - - -
e50c0be9 by Alan Zimmerman at 2026-09-03T22:59:45+01:00
EPA: HsList attempt WIP
- - - - -
20edaa07 by Alan Zimmerman at 2026-09-03T22:59:45+01:00
Enable ppr test for Haddock1. It currently fails
- - - - -
3e4fb6e4 by Alan Zimmerman at 2026-09-03T22:59:45+01:00
WIP on removing NoEpAnn. Likely abandon
- - - - -
346b41c1 by Alan Zimmerman at 2026-09-03T22:59:45+01:00
EPA: Add an overview doc for exact printing
- - - - -
86403107 by Simon Peyton Jones at 2026-09-03T22:59:45+01:00
Added an intro section
- - - - -
44 changed files:
- ANNLIST-LAYOUT-PLAN.md
- + ExactPrint.md
- LAYOUT-SCOPE-PLAN.md
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/Main/Interactive.hs
- compiler/GHC/Hs.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/DocString.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/ImpExp.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Stats.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Rename/Splice.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Types/Origin.hs
- compiler/GHC/ThToHs.hs
- compiler/Language/Haskell/Syntax.hs
- compiler/Language/Haskell/Syntax/Basic.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Expr.hs
- ghc/GHCi/UI.hs
- testsuite/tests/haddock/should_compile_flag_haddock/T17544.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/DumpSemis.stderr
- testsuite/tests/parser/should_compile/T20452.stderr
- testsuite/tests/printer/Makefile
- + testsuite/tests/printer/Test20297.expected.hs
- testsuite/tests/printer/Test20297.hs
- testsuite/tests/printer/Test20297.stdout
- testsuite/tests/printer/Test24533.stdout
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/check-exact/Parsers.hs
- utils/check-exact/Transform.hs
- utils/check-exact/Utils.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/cb9f848c1bdea8ad4dc5daf6daa183…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/cb9f848c1bdea8ad4dc5daf6daa183…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/rafl/hpc-instances] 5 commits: hpc: Make instances available in TickTransEnv
by Florian Ragwitz (@rafl) 04 Sep '26
by Florian Ragwitz (@rafl) 04 Sep '26
04 Sep '26
Florian Ragwitz pushed to branch wip/rafl/hpc-instances at Glasgow Haskell Compiler / GHC
Commits:
ae204bf8 by Florian Ragwitz at 2026-09-03T12:11:24-07:00
hpc: Make instances available in TickTransEnv
- - - - -
844fcc29 by Florian Ragwitz at 2026-09-03T12:11:24-07:00
hpc: Capture which method Ids belong to which dictionary function Id
- - - - -
7ca944f1 by Florian Ragwitz at 2026-09-03T12:11:25-07:00
hpc: Carry method id mapping in TcGblEnv
- - - - -
54575c5a by Florian Ragwitz at 2026-09-03T12:11:25-07:00
hpc: pass instance method mapping to addTicksToBinds and propagate ABEs
- - - - -
afe5fe80 by Florian Ragwitz at 2026-09-03T12:11:25-07:00
hpc: Do not create top-level boxes for generated instance methods
Users care about which of their written methods are or aren't covered, not
whether all of the inherited methods are covered as well. Those should be
covered where they are implemented.
This set of changes achieves the above by stopping to generate top-level boxes
which will often appear as uncovered with no clear indication as to why, and no
way to fix other than excercising code the user has not written.
- - - - -
6 changed files:
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Utils/Monad.hs
Changes:
=====================================
compiler/GHC/HsToCore.hs
=====================================
@@ -147,6 +147,7 @@ deSugar hsc_env
tcg_tcs = tcs,
tcg_default_exports = defaults,
tcg_insts = insts,
+ tcg_inst_meths = inst_meths,
tcg_fam_insts = fam_insts,
tcg_complete_matches = complete_matches,
tcg_self_boot = self_boot
@@ -170,7 +171,7 @@ deSugar hsc_env
(hsc_logger hsc_env)
(initTicksConfig (hsc_dflags hsc_env))
mod mod_loc
- export_set (typeEnvTyCons type_env) binds
+ export_set (typeEnvTyCons type_env) inst_meths binds
else return (binds, Nothing)
; let modBreaks
| Just (_, _, breakpointSpecs) <- m_tickInfo
=====================================
compiler/GHC/HsToCore/Ticks.hs
=====================================
@@ -24,6 +24,7 @@ import GHC.Unit
import GHC.Core.Type
import GHC.Core.TyCon
+import GHC.Core.InstEnv
import GHC.Data.Maybe
import GHC.Data.FastString
@@ -100,11 +101,12 @@ addTicksToBinds
-- isExportedId doesn't work yet (the desugarer
-- hasn't set it), so we have to work from this set.
-> [TyCon] -- ^ Type constructors in this module
+ -> IdEnv DFunId
-> LHsBinds GhcTc
-> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick, SizedSeq Tick))
addTicksToBinds logger cfg
- mod mod_loc exports tyCons binds
+ mod mod_loc exports tyCons inst_meths binds
| let passes = ticks_passes cfg
, not (null passes)
, Just orig_file <- ml_hs_file mod_loc = do
@@ -129,6 +131,7 @@ addTicksToBinds logger cfg
, this_mod = mod
, tickishType = tickish
, recSelBinds = emptyVarEnv
+ , instMeths = inst_meths
}
(binds',_,st') = unTM (addTickLHsBinds binds) env st
in (binds', st')
@@ -231,7 +234,7 @@ addTickLHsBind :: LHsBind GhcTc -> TM (LHsBind GhcTc)
addTickLHsBind (L pos (XHsBindsLR bind@(AbsBinds { abs_binds = binds
, abs_exports = abs_exports
}))) =
- withEnv (add_rec_sels . add_inlines . add_exports) $ do
+ withEnv (add_inst_meths . add_rec_sels . add_inlines . add_exports) $ do
binds' <- addTickLHsBinds binds
return $ L pos $ XHsBindsLR $ bind { abs_binds = binds' }
where
@@ -259,19 +262,24 @@ addTickLHsBind (L pos (XHsBindsLR bind@(AbsBinds { abs_binds = binds
| ABE{ abe_poly, abe_mono } <- abs_exports
, RecSelId{} <- [idDetails abe_poly] ] }
+ add_inst_meths env =
+ env{ instMeths = instMeths env `extendVarEnvList`
+ [ (abe_mono, dfun)
+ | ABE{ abe_poly, abe_mono } <- abs_exports
+ , Just dfun <- [lookupVarEnv (instMeths env) abe_poly] ] }
+
addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches }))) = do
let name = getOccString id
decl_path <- getPathEntry
density <- getDensity
+ env <- getEnv
- inline_ids <- liftM inlines getEnv
-- See Note [inline sccs]
let inline = isInlinePragma (idInlinePragma id)
- || id `elemVarSet` inline_ids
+ || id `elemVarSet` inlines env
-- See Note [inline sccs]
- tickish <- tickishType `liftM` getEnv
- case tickish of { ProfNotes | inline -> return (L pos funBind); _ -> do
+ case tickishType env of { ProfNotes | inline -> return (L pos funBind); _ -> do
-- See Note [Record-selector ticks]
selTicks <- recSelTick id
@@ -294,8 +302,12 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches
toplev = null decl_path
exported = idName id `elemNameSet` exported_names
- tick <- if not blackListed &&
- shouldTickBind density toplev exported simple inline
+ let generatedInstMeth = id `elemVarEnv` instMeths env
+ && isGenerated (mg_origin (mg_ext matches))
+
+ tick <- if not generatedInstMeth
+ && not blackListed
+ && shouldTickBind density toplev exported simple inline
then
bindTick density name (locA pos) fvs
else
@@ -1098,6 +1110,7 @@ data TickTransEnv = TTE { fileName :: FastString
, this_mod :: Module
, tickishType :: TickishType
, recSelBinds :: IdEnv DVarSet
+ , instMeths :: IdEnv DFunId
}
-- deriving Show
=====================================
compiler/GHC/Tc/Module.hs
=====================================
@@ -1770,7 +1770,7 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
-- Second pass over class and instance declarations,
-- now using the kind-checked decls
traceTc "Tc6" empty ;
- inst_binds <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;
+ (inst_binds, inst_meths) <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;
-- Foreign exports
traceTc "Tc7" empty ;
@@ -1802,8 +1802,9 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
, tcg_anns = tcg_anns tcg_env ++ annotations
, tcg_ann_env = extendAnnEnvList (tcg_ann_env tcg_env) annotations
, tcg_fords = tcg_fords tcg_env ++ foe_decls ++ fi_decls
- , tcg_dus = tcg_dus tcg_env `plusDU` usesOnly fo_fvs } } ;
+ , tcg_dus = tcg_dus tcg_env `plusDU` usesOnly fo_fvs
-- tcg_dus: see Note [Newtype constructor usage in foreign declarations]
+ , tcg_inst_meths = tcg_inst_meths tcg_env `plusVarEnv` inst_meths } } ;
-- See Note [Newtype constructor usage in foreign declarations]
addUsedGREs NoDeprecationWarnings (bagToList fo_gres) ;
=====================================
compiler/GHC/Tc/TyCl/Instance.hs
=====================================
@@ -1282,7 +1282,7 @@ takes a slightly different approach.
********************************************************************* -}
tcInstDecls2 :: [LTyClDecl GhcRn] -> [InstInfo GhcRn]
- -> TcM (LHsBinds GhcTc)
+ -> TcM (LHsBinds GhcTc, IdEnv DFunId)
-- (a) From each class declaration,
-- generate any default-method bindings
-- (b) From each instance decl
@@ -1299,11 +1299,11 @@ tcInstDecls2 tycl_decls inst_decls
-- Add the default method Ids (again)
-- (they were already added in GHC.Tc.TyCl.Utils.tcAddImplicits)
-- See Note [Default methods in the type environment]
- ; inst_binds_s <- tcExtendGlobalValEnv dm_ids $
- mapM tcInstDecl2 inst_decls
+ ; (inst_binds_s, inst_meths_s) <- unzip <$> (tcExtendGlobalValEnv dm_ids $
+ mapM tcInstDecl2 inst_decls)
-- Done
- ; return (dm_binds ++ concat inst_binds_s) }
+ ; return (dm_binds ++ concat inst_binds_s, plusVarEnvList inst_meths_s) }
{- Note [Default methods in the type environment]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1319,12 +1319,12 @@ So right here in tcInstDecls2 we must re-extend the type envt with
the default method Ids replete with their INLINE pragmas. Urk.
-}
-tcInstDecl2 :: InstInfo GhcRn -> TcM (LHsBinds GhcTc)
+tcInstDecl2 :: InstInfo GhcRn -> TcM (LHsBinds GhcTc, IdEnv DFunId)
-- Returns a binding for the dfun
tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
- = recoverM (return emptyLHsBinds) $
- setSrcSpan loc $
- addErrCtxt (instDeclCtxt2 dfun_ty) $
+ = recoverM (return (emptyLHsBinds, emptyVarEnv)) $
+ setSrcSpan loc $
+ addErrCtxt (instDeclCtxt2 dfun_ty) $
do { -- Instantiate the instance decl with skolem constants
(skol_info, inst_tyvars, dfun_theta, clas, inst_tys) <- tcSkolDFunType dfun_ty
; dfun_ev_vars <- newEvVars dfun_theta
@@ -1342,7 +1342,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
-- See Note [Typechecking plan for instance declarations]
; dfun_ev_binds_var <- newTcEvBinds
; let dfun_ev_binds = TcEvBinds dfun_ev_binds_var
- ; (tclvl, (sc_meth_ids, sc_meth_binds, sc_meth_implics))
+ ; (tclvl, (sc_meth_ids, sc_meth_binds, sc_meth_implics, meth_ids))
<- pushTcLevelM $
do { (sc_ids, sc_binds, sc_implics)
<- tcSuperClasses skol_info dfun_id clas inst_tyvars
@@ -1356,7 +1356,8 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
; return ( sc_ids ++ meth_ids
, sc_binds ++ meth_binds
- , sc_implics `unionBags` meth_implics ) }
+ , sc_implics `unionBags` meth_implics
+ , meth_ids ) }
; imp <- newImplication
; emitImplication $
@@ -1413,7 +1414,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
, abs_binds = [dict_bind]
, abs_sig = True }
- ; return (L loc' main_bind : sc_meth_binds)
+ ; return (L loc' main_bind : sc_meth_binds, mkVarEnv $ (,dfun_id) <$> meth_ids)
}
where
dfun_id = instanceDFunId ispec
=====================================
compiler/GHC/Tc/Types.hs
=====================================
@@ -157,6 +157,7 @@ import GHC.Types.Name.Env
import GHC.Types.Name.Set
import GHC.Types.Avail
import GHC.Types.Var
+import GHC.Types.Var.Env
import GHC.Types.TypeEnv
import GHC.Types.SourceFile
import GHC.Types.SrcLoc
@@ -528,6 +529,7 @@ data TcGblEnv
-- ^ Instance envt for all /home-package/ modules;
-- Includes the dfuns in tcg_insts
-- NB. BangPattern is to fix a leak, see #15111
+ tcg_inst_meths :: IdEnv DFunId,
tcg_fam_inst_env :: !FamInstEnv, -- ^ Ditto for family instances
-- NB. BangPattern is to fix a leak, see #15111
tcg_ann_env :: AnnEnv, -- ^ And for annotations
=====================================
compiler/GHC/Tc/Utils/Monad.hs
=====================================
@@ -409,6 +409,7 @@ initTcGblEnv hsc_env hsc_src keep_rn_syntax mod loc =
, tcg_knot_vars = hsc_type_env_vars hsc_env
, tcg_known_key_maps = known_key_maps_var
, tcg_inst_env = emptyInstEnv
+ , tcg_inst_meths = emptyVarEnv
, tcg_fam_inst_env = emptyFamInstEnv
, tcg_ann_env = emptyAnnEnv
, tcg_complete_match_env = []
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c5eaffb8b1932973d0d3f3809209c1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c5eaffb8b1932973d0d3f3809209c1…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
04 Sep '26
Florian Ragwitz pushed new branch wip/rafl/hpc-instances at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/rafl/hpc-instances
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/az/epa-tidy-locatedxxx-22] 3 commits: Add -Wimplicit-field-strictness (#16836)
by Alan Zimmerman (@alanz) 04 Sep '26
by Alan Zimmerman (@alanz) 04 Sep '26
04 Sep '26
Alan Zimmerman pushed to branch wip/az/epa-tidy-locatedxxx-22 at Glasgow Haskell Compiler / GHC
Commits:
9e7739ab by Simon Jakobi at 2026-09-03T13:45:43-04:00
Add -Wimplicit-field-strictness (#16836)
This opt-in warning fires when a data constructor field lacks an
explicit strictness annotation (`!` or `~`). It complements the
LazyFieldAnnotations extension (4762a8bf30f) from GHC proposal 752,
which makes `~` annotations available for this purpose.
Deciding which fields to report requires their levity, so the check
runs after typechecking. To keep the noise down, the diagnostic is
emitted once per data declaration, grouped by constructor.
Closes #16836.
Assisted-by: Claude Fable 5
- - - - -
6a44d591 by mangoiv at 2026-09-03T13:46:22-04:00
simplifier: remove a bogus `assert` in `rebuild_app'` in `GHC.CoreToStg.Prep.cpeApp`.
Prior to this commit
commit 08bc245be70d95801bc1138804ed1de9474fbdc0
Author: sheaf <sam.derbyshire(a)gmail.com>
Date: Sat Feb 28 16:30:43 2026 +0100
Clean up join points, casts & ticks
This commit shores up the logic dealing with casts and ticks occurring
in between a join point binding and a jump
any `PlaceRuntime` ticks we observed were profiling ticks, even though that
isn't necessary.
The more liberal rules in the above commit allow e.g. breakpoint ticks
(which are valid PlaceRuntime ticks) to legitimately appear in an argument
position.
Fixes #27556
- - - - -
d7fd9a06 by Alan Zimmerman at 2026-09-03T19:10:26+00:00
EPA Fix HsCmdDo exact print with comments
Exact printing of HsCmdDo was ignoring the location for the do
statements, and this is an annotation that can have comments in it.
Update it so we print the statements as a unit, including any
comments.
Also add the result of auditing that we capture comments in all needed
places, noting that the remaining Anno SrcSpan instances are benign.
- - - - -
29 changed files:
- + changelog.d/27556
- + changelog.d/implicit-field-strictness-warning
- changelog.d/lazy-field-annotations
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Hs/Extension/Pass.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
- compiler/GHC/Types/Tickish.hs
- docs/users_guide/exts/strict.rst
- docs/users_guide/using-warnings.rst
- + testsuite/tests/simplCore/should_compile/T27556.hs
- + testsuite/tests/simplCore/should_compile/T27556.script
- testsuite/tests/simplCore/should_compile/all.T
- + 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/T16836d.hs
- + testsuite/tests/warnings/should_compile/T16836d.stderr
- testsuite/tests/warnings/should_compile/all.T
- utils/check-exact/ExactPrint.hs
Changes:
=====================================
changelog.d/27556
=====================================
@@ -0,0 +1,5 @@
+section: compiler
+synopsis: Remove a too strict assert in coreprep; fixes a bug where debug builds
+ of GHC would fail to compile correctly optimized programs.
+mrs: !16558
+issues: #27556
=====================================
changelog.d/implicit-field-strictness-warning
=====================================
@@ -0,0 +1,10 @@
+section: compiler
+synopsis: Add `-Wimplicit-field-strictness`
+issues: #16836
+mrs: !16555
+
+description: {
+ The new opt-in warning :ghc-flag:`-Wimplicit-field-strictness` reports
+ data constructor fields that lack an explicit strictness annotation
+ (``!`` or ``~``).
+}
=====================================
changelog.d/lazy-field-annotations
=====================================
@@ -11,4 +11,7 @@ description: {
continues to control the default strictness of unannotated fields.
See `GHC Proposal #752 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0752-l…>`_.
+
+ Also note the new opt-in :ghc-flag:`-Wimplicit-field-strictness` warning, which
+ reports fields lacking an explicit annotation.
}
=====================================
compiler/GHC/CoreToStg/Prep.hs
=====================================
@@ -1260,10 +1260,9 @@ cpeApp top_env expr
-- See Note [Ticks and mandatory eta expansion]
AITick tickish
- | tickishPlace tickish == PlaceRuntime
+ | PlaceRuntime <- tickishPlace tickish
, req_depth > 0
- -> assert (isProfTick tickish) $
- rebuild_app' env as fun' floats ss (tickish:rt_ticks) req_depth
+ -> rebuild_app' env as fun' floats ss (tickish:rt_ticks) req_depth
| otherwise
-- See [Floating Ticks in CorePrep]
-> rebuild_app' env as fun' (snocFloat floats (FloatTick tickish)) ss rt_ticks req_depth
=====================================
compiler/GHC/Driver/Flags.hs
=====================================
@@ -1142,6 +1142,7 @@ data WarningFlag =
| Opt_WarnUnrecognisedModifiers -- ^ @since 10.0
| Opt_WarnSemaphoreOpenFailure -- Since 10.0.1
| Opt_WarnDefaultedCallStack -- ^ @since 10.2
+ | Opt_WarnImplicitFieldStrictness -- ^ @since 10.2
deriving (Eq, Ord, Show, Enum, Bounded)
-- | Return the names of a WarningFlag
@@ -1251,6 +1252,7 @@ warnFlagNames wflag = case wflag of
Opt_WarnTypeEqualityRequiresOperators -> "type-equality-requires-operators" :| []
Opt_WarnMissingRoleAnnotations -> "missing-role-annotations" :| []
Opt_WarnImplicitRhsQuantification -> "implicit-rhs-quantification" :| []
+ Opt_WarnImplicitFieldStrictness -> "implicit-field-strictness" :| []
Opt_WarnIncompleteExportWarnings -> "incomplete-export-warnings" :| []
Opt_WarnIncompleteRecordSelectors -> "incomplete-record-selectors" :| []
Opt_WarnBadlyLevelledTypes -> "badly-levelled-types" :| []
=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -2449,6 +2449,7 @@ wWarningFlagsDeps = [minBound..maxBound] >>= \x -> case x of
Opt_WarnUnrecognisedModifiers -> warnSpec x
Opt_WarnSemaphoreOpenFailure -> warnSpec x
Opt_WarnDefaultedCallStack -> warnSpec x
+ Opt_WarnImplicitFieldStrictness -> warnSpec x
warningGroupsDeps :: [(Deprecation, FlagSpec WarningGroup)]
warningGroupsDeps = map mk warningGroups
=====================================
compiler/GHC/Hs/Doc.hs
=====================================
@@ -58,6 +58,7 @@ import Language.Haskell.Syntax.Doc
import Language.Haskell.Syntax.Extension
import Language.Haskell.Syntax.Module.Name
+-- Exact print annotations ignore LHsDoc, so bare SrcSpan is fine
type instance Anno (WithHsDocIdentifiers (HsDocString (GhcPass pass)) (GhcPass pass)) = SrcSpan
deriving instance (Data pass, Data (LIdP pass), Data a) => Data (WithHsDocIdentifiers a pass)
=====================================
compiler/GHC/Hs/Extension/Pass.hs
=====================================
@@ -46,6 +46,7 @@ type instance XRec (GhcPass p) a = XRecGhc a
-- but pass-independent, source location
type XRecGhc a = GenLocated (Anno a) a
+-- Exact print annotations ignore LHsDoc, so bare SrcSpan is fine
type instance Anno (HsDocString (GhcPass _)) = SrcSpan
type instance Anno HsDocStringChunk = SrcSpan
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -1384,6 +1384,21 @@ instance Diagnostic TcRnMessage where
hang (text "Missing role annotation" <> colon)
2 (text "type role" <+> ppr name <+> hsep (map ppr roles))
+ TcRnImplicitFieldStrictness _lazy_anns cons -> mkSimpleDecorated $
+ hang (text "These constructor fields lack an explicit strictness annotation" <> colon)
+ 2 (vcat (map ppr_con (NE.toList cons)))
+ where
+ ppr_con (con, fields) =
+ bullet <+> text "In" <+> quotes (ppr con) <> colon <+> ppr_fields (NE.toList fields)
+ ppr_fields fields
+ | let names = [n | ImplicitStrictnessRecField n <- fields]
+ , not (null names)
+ = text "field" <> plural names <+> quotedListWithAnd (map ppr names)
+ | otherwise
+ = let poss = [i | ImplicitStrictnessPosField i <- fields]
+ in text "field" <> plural poss
+ <+> unquotedListWith (text "and") (map int poss)
+
TcRnIllformedTypePattern p
-> mkSimpleDecorated $
hang (text "Ill-formed type pattern:") 2 (ppr p)
@@ -2693,6 +2708,8 @@ instance Diagnostic TcRnMessage where
-> ErrorWithoutFlag
TcRnMissingRoleAnnotation{}
-> WarningWithFlag Opt_WarnMissingRoleAnnotations
+ TcRnImplicitFieldStrictness{}
+ -> WarningWithFlag Opt_WarnImplicitFieldStrictness
TcRnIllegalInvisTyVarBndr{}
-> ErrorWithoutFlag
TcRnIllegalWildcardTyVarBndr{}
@@ -3428,6 +3445,12 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnMissingRoleAnnotation{}
-> noHints
+ TcRnImplicitFieldStrictness lazy_anns _
+ -> SuggestExplicitFieldStrictness
+ : [ useExtensionInOrderTo
+ (text "to allow" <+> quotes (char '~') <+> text "annotations")
+ LangExt.LazyFieldAnnotations
+ | not lazy_anns ]
TcRnIllegalInvisTyVarBndr{}
-> [suggestExtension LangExt.TypeAbstractions]
TcRnIllegalWildcardTyVarBndr{}
=====================================
compiler/GHC/Tc/Errors/Types.hs
=====================================
@@ -123,6 +123,7 @@ module GHC.Tc.Errors.Types (
, TypeSyntax(..)
, typeSyntaxExtension
, SuggestLinear(..)
+ , ImplicitStrictnessField(..)
-- * Errors for hs-boot and signature files
, BadBootDecls(..)
@@ -4235,6 +4236,23 @@ data TcRnMessage where
-}
TcRnMissingRoleAnnotation :: Name -> [Role] -> TcRnMessage
+
+ {-| TcRnImplicitFieldStrictness is a warning that occurs when a data
+ constructor field lacks an explicit strictness annotation (@!@ or @~@)
+
+ Controlled by flags:
+ - Wimplicit-field-strictness
+
+ Test cases:
+ T16836a, T16836b, T16836c, T16836d
+
+ -}
+ TcRnImplicitFieldStrictness
+ :: Bool -- ^ whether @LazyFieldAnnotations@ is enabled
+ -> NonEmpty (Name, NonEmpty ImplicitStrictnessField)
+ -- ^ per data constructor, the fields lacking annotations
+ -> TcRnMessage
+
{-| TcRnPatersonCondFailure is an error that occurs when an instance
declaration fails to conform to the Paterson conditions. Which particular condition
fails depends on the constructor of PatersonCondFailure
@@ -6399,6 +6417,14 @@ data PatSynInvalidRhsReason
| PatSynUnboundVar !Name
deriving (Generic)
+-- | A constructor field lacking an explicit strictness annotation, as
+-- reported by 'TcRnImplicitFieldStrictness'.
+data ImplicitStrictnessField
+ -- | A record field
+ = ImplicitStrictnessRecField FieldLabelString
+ -- | A positional argument (1-based index)
+ | ImplicitStrictnessPosField Int
+
data BadFieldAnnotationReason where
{-| A lazy data type field annotation (~) was used without enabling the
extension LazyFieldAnnotations.
=====================================
compiler/GHC/Tc/TyCl.hs
=====================================
@@ -5022,6 +5022,16 @@ checkValidTyCon tc
; mapM_ (checkValidDataCon dflags ex_ok tc) data_cons
; mapM_ (checkPartialRecordField data_cons) (tyConFieldLabels tc)
+ ; warn_implicit_strictness <- woptM Opt_WarnImplicitFieldStrictness
+ ; when (warn_implicit_strictness
+ && not (isNewTyCon tc)
+ && not (isTypeDataTyCon tc)) $
+ whenIsJust (NE.nonEmpty (mapMaybe conImplicitStrictnessFields data_cons)) $
+ \offenders ->
+ do { lazy_anns <- xoptM LangExt.LazyFieldAnnotations
+ ; addDiagnosticTc $
+ TcRnImplicitFieldStrictness lazy_anns offenders }
+
-- Check that fields with the same name share a type
; mapM_ check_fields groups }}
where
@@ -5072,6 +5082,29 @@ checkValidTyCon tc
res2 = dataConOrigResTy con2
fty2 = dataConFieldType con2 lbl
+-- | For a given data constructor, collect the fields to report for
+-- @-Wimplicit-field-strictness@.
+--
+-- Only fields whose type is known to be lifted are collected: unlifted
+-- fields are unconditionally strict, and annotating one with @!@ or
+-- @~@ would trigger @-Wredundant-strictness-flags@.
+conImplicitStrictnessFields :: DataCon -> Maybe (Name, NonEmpty ImplicitStrictnessField)
+conImplicitStrictnessFields con
+ | Just ne_fields <- NE.nonEmpty fields
+ = Just (dataConName con, ne_fields)
+ | otherwise
+ = Nothing
+ where
+ fld_refs = case dataConFieldLabels con of
+ [] -> map ImplicitStrictnessPosField [1..]
+ lbls -> map (ImplicitStrictnessRecField . flLabel) lbls
+ fields = [ ref
+ | (ref, arg_ty, HsSrcBang _ _ NoSrcStrict)
+ <- zip3 fld_refs
+ (map scaledThing (dataConOrigArgTys con))
+ (dataConSrcBangs con)
+ , typeLevity_maybe arg_ty == Just Lifted ]
+
checkPartialRecordField :: [DataCon] -> FieldLabel -> TcM ()
-- Checks the partial record field selector, and warns.
-- See Note [Checking partial record field]
=====================================
compiler/GHC/Types/Error/Codes.hs
=====================================
@@ -542,6 +542,7 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnNegativeNumTypeLiteral" = 93632
GhcDiagnosticCode "TcRnUnusedQuantifiedTypeVar" = 54180
GhcDiagnosticCode "TcRnMissingRoleAnnotation" = 65490
+ GhcDiagnosticCode "TcRnImplicitFieldStrictness" = 47032
GhcDiagnosticCode "TcRnUntickedPromotedThing" = 49957
GhcDiagnosticCode "TcRnIllegalBuiltinSyntax" = 39716
=====================================
compiler/GHC/Types/Hint.hs
=====================================
@@ -343,6 +343,14 @@ data GhcHint
-}
| SuggestAddStandaloneKindSignature Name
+ {-| Suggests to annotate each constructor field with explicit strictness
+ (@!@ or @~@).
+
+ Triggered by: 'GHC.Tc.Errors.Types.TcRnImplicitFieldStrictness'
+ Test case(s): warnings/should_compile/T16836a
+ -}
+ | SuggestExplicitFieldStrictness
+
{-| Suggests the user to fill in the wildcard constraint to
disambiguate which constraint that is.
=====================================
compiler/GHC/Types/Hint/Ppr.hs
=====================================
@@ -185,6 +185,9 @@ instance Outputable GhcHint where
-> text "Use a standalone deriving declaration instead"
SuggestAddStandaloneKindSignature name
-> text "Add a standalone kind signature for" <+> quotes (ppr name)
+ SuggestExplicitFieldStrictness
+ -> text "Annotate each field with" <+> quotes (char '!')
+ <+> text "(strict) or" <+> quotes (char '~') <+> text "(lazy)"
SuggestFillInWildcardConstraint
-> text "Fill in the wildcard constraint yourself"
SuggestAppropriateTHTick ns
=====================================
compiler/GHC/Types/Tickish.hs
=====================================
@@ -13,7 +13,6 @@ module GHC.Types.Tickish (
mkNoCount,
mkNoScope,
tickishIsCode,
- isProfTick,
TickishPlacement(..),
tickishPlace,
tickishContains,
@@ -545,10 +544,6 @@ tickishIsCode ProfNote{} = True
tickishIsCode Breakpoint{} = True
tickishIsCode HpcTick{} = True
-isProfTick :: GenTickish pass -> Bool
-isProfTick ProfNote{} = True
-isProfTick _ = False
-
-- | Governs the kind of expression that the tick gets placed on when
-- annotating for example using @mkTick@. If we find that we want to
-- put a tickish on an expression ruled out here, we try to float it
=====================================
docs/users_guide/exts/strict.rst
=====================================
@@ -194,6 +194,9 @@ The ``~`` annotation must be written in prefix form::
See `GHC Proposal #229 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-w…>`__
for the precise rules.
+See also :ghc-flag:`-Wimplicit-field-strictness`, which warns about
+fields lacking an explicit annotation.
+
.. _strict-data:
Strict-by-default data types
=====================================
docs/users_guide/using-warnings.rst
=====================================
@@ -2505,6 +2505,21 @@ of ``-W(no-)*``.
In other words the type-class role cannot be accidentally left
representational or phantom, which could affected the code correctness.
+.. ghc-flag:: -Wimplicit-field-strictness
+ :shortdesc: warn when constructor fields lack explicit strictness annotations
+ :type: dynamic
+ :reverse: -Wno-implicit-field-strictness
+ :category:
+
+ :since: 10.2.1
+ :default: off
+
+ .. index::
+ single: strictness annotations, missing
+
+ This warning reports data constructor fields that lack an explicit
+ strictness annotation (``!`` or ``~``).
+
.. ghc-flag:: -Wimplicit-rhs-quantification
:shortdesc: warn when type variables on the RHS of a type synonym are implicitly quantified
:type: dynamic
=====================================
testsuite/tests/simplCore/should_compile/T27556.hs
=====================================
@@ -0,0 +1,4 @@
+import Control.Exception
+
+main = mask $ \restore -> restore (pure ())
+
=====================================
testsuite/tests/simplCore/should_compile/T27556.script
=====================================
@@ -0,0 +1 @@
+:l T27556
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -611,3 +611,4 @@ test('T27296', [], makefile_test, ['T27296'])
test('T27296b', [], makefile_test, ['T27296b'])
test('T27589', [grep_errmsg(r'wombat')], compile, ['-O -ddump-simpl -dno-typeable-binds -dsuppress-uniques'])
test('T27590', [grep_errmsg(r'wombat')], compile, ['-O -ddump-simpl -dno-typeable-binds -dsuppress-uniques'])
+test('T27556', [only_ways('ghci'), extra_hc_opts('-O -fno-unoptimized-core-for-interpreter')], ghci_script, ['T27556.script'])
=====================================
testsuite/tests/warnings/should_compile/T16836a.hs
=====================================
@@ -0,0 +1,37 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+module T16836a where
+
+-- plain multi-constructor data
+-- warns for both constructors
+data T a = MkT a Bool
+ | MkT2 !Int a
+
+-- record with a shared field group
+-- warns for x, y and z; not for b
+data R = MkR { x, y :: Int, z :: Char, b :: !Bool }
+
+-- infix constructor
+-- warns for the first argument
+data I = Int :+: !Bool
+
+-- GADT syntax
+-- warns for the first argument
+data G a where
+ MkG :: Int -> !Bool -> G a
+
+-- GADT record syntax
+-- warns for gx
+data GR a where
+ MkGR :: { gx :: Int, gy :: !Bool } -> GR a
+
+-- data family instance
+-- warns
+data family F a
+data instance F Int = MkF Char
+
+-- fully annotated
+-- doesn't warn
+data S = MkS !Int !Bool
=====================================
testsuite/tests/warnings/should_compile/T16836a.stderr
=====================================
@@ -0,0 +1,55 @@
+T16836a.hs:9:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkT’: fields 1 and 2
+ • In ‘MkT2’: field 2
+ • In the data type declaration for ‘T’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:14:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkR’: fields ‘x’, ‘y’ and ‘z’
+ • In the data type declaration for ‘R’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:18:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘:+:’: field 1
+ • In the data type declaration for ‘I’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:22:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkG’: field 1
+ • In the data type declaration for ‘G’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:27:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkGR’: field ‘gx’
+ • In the data type declaration for ‘GR’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:33:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkF’: field 1
+ • In the data family instance declaration for ‘F’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
=====================================
testsuite/tests/warnings/should_compile/T16836b.hs
=====================================
@@ -0,0 +1,25 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeData #-}
+{-# LANGUAGE EmptyDataDecls #-}
+{-# LANGUAGE LazyFieldAnnotations #-}
+module T16836b where
+
+-- fully annotated declarations don't warn
+data T a = MkT ~a !Bool
+data R = MkR { x, y :: !Int, z :: ~Char }
+data G a where
+ MkG :: !Int -> ~Bool -> G a
+data family F a
+data instance F Int = MkF !Char
+
+-- newtypes can't have annotations; exempt
+newtype N = MkN Int
+
+-- 'type data' can't have annotations; exempt
+type data TD = MkTD Bool
+
+-- no fields, nothing to annotate
+data E
+data Nullary = A | B
=====================================
testsuite/tests/warnings/should_compile/T16836c.hs
=====================================
@@ -0,0 +1,6 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE StrictData #-}
+module T16836c where
+
+-- unannotated fields warn under StrictData too
+data T a = MkT a !Bool ~Char
=====================================
testsuite/tests/warnings/should_compile/T16836c.stderr
=====================================
@@ -0,0 +1,6 @@
+T16836c.hs:6:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkT’: field 1
+ • In the data type declaration for ‘T’
+ Suggested fix: Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+
=====================================
testsuite/tests/warnings/should_compile/T16836d.hs
=====================================
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedDatatypes #-}
+module T16836d where
+
+import GHC.Exts
+
+-- unlifted fields can't be usefully annotated; exempt
+data P = MkP Int# (# Int, Int #)
+
+type UD :: UnliftedType
+data UD = MkUD
+
+-- a field of an unlifted data type is exempt too
+data Q = MkQ UD
+
+-- mixed constructor
+-- warns only for the lifted field 2
+data M = MkM Int# Int
=====================================
testsuite/tests/warnings/should_compile/T16836d.stderr
=====================================
@@ -0,0 +1,9 @@
+T16836d.hs:20:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkM’: field 2
+ • In the data type declaration for ‘M’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
=====================================
testsuite/tests/warnings/should_compile/all.T
=====================================
@@ -91,3 +91,7 @@ test('T25901_imp_unused_3', [extra_files(['T25901_helper_3.hs'])], multimod_comp
test('T25901_imp_unused_4', normal, compile, ['-Wunused-imports'])
test('T25901_imp_dodgy_1', [extra_files(['T25901_helper_1.hs'])], multimod_compile, ['T25901_imp_dodgy_1', '-v0 -Wdodgy-imports'])
test('T25901_imp_dodgy_2', [extra_files(['T25901_helper_2.hs'])], multimod_compile, ['T25901_imp_dodgy_2', '-v0 -Wdodgy-imports'])
+test('T16836a', normal, compile, [''])
+test('T16836b', normal, compile, [''])
+test('T16836c', normal, compile, [''])
+test('T16836d', normal, compile, [''])
=====================================
utils/check-exact/ExactPrint.hs
=====================================
@@ -3397,13 +3397,13 @@ instance ExactPrint (HsCmd GhcPs) where
e' <- markAnnotated e
return (HsCmdLet (tkLet', tkIn') binds' e')
- exact (HsCmdDo (an0,loc) (L l es)) = do
+ exact (HsCmdDo (an0,loc) es) = do
debugM $ "HsCmdDo"
loc' <- printStringAtAA loc "do"
(an1,es') <- markAnnList' an0 $ do
- ee <- mapM markAnnotated es
+ ee <- markAnnotated es
return ee
- return (HsCmdDo (an1,loc') (L l es'))
+ return (HsCmdDo (an1,loc') es')
-- ---------------------------------------------------------------------
@@ -4462,10 +4462,10 @@ instance ExactPrint [LocatedA (StmtLR GhcPs GhcPs (LocatedA (HsCmd GhcPs)))] whe
Just (initStmts, ls@(L _ (LastStmt _ _body _ _))) -> do
debugM $ "LocatedL [ExprLStmt: snocView"
ls' <- markAnnotated ls
- initStmts' <- markAnnotated initStmts
+ initStmts' <- mapM markAnnotated initStmts
return (initStmts' ++ [ls'])
_ -> do
- stmts' <- markAnnotated stmts
+ stmts' <- mapM markAnnotated stmts
return stmts'
instance ExactPrint [Located HsDocStringChunk] where
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/6af3089f1929befb0b98143b10ad44…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/6af3089f1929befb0b98143b10ad44…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: Add -Wimplicit-field-strictness (#16836)
by Marge Bot (@marge-bot) 04 Sep '26
by Marge Bot (@marge-bot) 04 Sep '26
04 Sep '26
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
9e7739ab by Simon Jakobi at 2026-09-03T13:45:43-04:00
Add -Wimplicit-field-strictness (#16836)
This opt-in warning fires when a data constructor field lacks an
explicit strictness annotation (`!` or `~`). It complements the
LazyFieldAnnotations extension (4762a8bf30f) from GHC proposal 752,
which makes `~` annotations available for this purpose.
Deciding which fields to report requires their levity, so the check
runs after typechecking. To keep the noise down, the diagnostic is
emitted once per data declaration, grouped by constructor.
Closes #16836.
Assisted-by: Claude Fable 5
- - - - -
6a44d591 by mangoiv at 2026-09-03T13:46:22-04:00
simplifier: remove a bogus `assert` in `rebuild_app'` in `GHC.CoreToStg.Prep.cpeApp`.
Prior to this commit
commit 08bc245be70d95801bc1138804ed1de9474fbdc0
Author: sheaf <sam.derbyshire(a)gmail.com>
Date: Sat Feb 28 16:30:43 2026 +0100
Clean up join points, casts & ticks
This commit shores up the logic dealing with casts and ticks occurring
in between a join point binding and a jump
any `PlaceRuntime` ticks we observed were profiling ticks, even though that
isn't necessary.
The more liberal rules in the above commit allow e.g. breakpoint ticks
(which are valid PlaceRuntime ticks) to legitimately appear in an argument
position.
Fixes #27556
- - - - -
e3134725 by Andrei Borzenkov at 2026-09-03T14:17:55-04:00
Parentheses in prefix GADT constructors (#27423)
Updated `splitLHsGadtTy` to allow looking
through the parentheses for inner binders. General example
of a code pattern that's allowed now:
data S a where
MkS :: (forall a. S a)
That should work now with any combination of nested
foralls and parentheses.
We don't perform parenthesis unwrapping for record
GADT constructors in accordance with GHC Proposal #402.
To this end `con_inner_bndrs` no longer stores plain forall
telescopes: `[HsForAllTelescope pass]` is replaced with
`[LHsGadtTelescope pass]`, a new `HsArg`-style type whose
`HsGadtForAll` holds an inner telescope and whose `HsGadtPar`
holds a pair of parentheses. The parentheses carry no meaning
for renaming or type checking; the only reason to record them
is exact-printing.
Updated `pprConDecl` to improve the `parse == parse . ppr . parse`
property of GADT pretty-printing.
The pretty printer can now output code that's similar to this:
data T a where
MkT1 :: (forall a. T a)
MkT2 :: forall . forall a. T a
These are special cases of inner forall binders
for prefix GADT constructors, when we have either
implicit or zero explicit outer binders.
- - - - -
4da8f180 by Evgeny Malyshev at 2026-09-03T14:18:03-04:00
HsPat: Add spacing to unary tuple patterns
Use hsep when printing unary boxed TuplePat applications so that the
MkSolo constructor is separated from its argument. The old hcat rendered
wildcard and parenthesized arguments as MkSolo_ and MkSolo().
Add T27034 to exercise the HsPat splice-dump path with wildcard and
variable arguments, and update existing affected golden output.
Fixes #27034
Assisted-By: OpenAI Codex
- - - - -
61 changed files:
- + changelog.d/27556
- + changelog.d/allow-gadt-prefix-con-parens
- + changelog.d/implicit-field-strictness-warning
- changelog.d/lazy-field-annotations
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/Tickish.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Type.hs
- docs/users_guide/exts/gadt_syntax.rst
- docs/users_guide/exts/strict.rst
- docs/users_guide/using-warnings.rst
- − testsuite/tests/gadt/T14320.stderr
- testsuite/tests/gadt/T18191.hs
- testsuite/tests/gadt/T18191.stderr
- + testsuite/tests/gadt/T27423a.hs
- + testsuite/tests/gadt/T27423b.hs
- + testsuite/tests/gadt/T27423b.stderr
- testsuite/tests/gadt/all.T
- testsuite/tests/printer/Makefile
- + testsuite/tests/printer/T27423c.hs
- testsuite/tests/printer/all.T
- + testsuite/tests/simplCore/should_compile/T27556.hs
- + testsuite/tests/simplCore/should_compile/T27556.script
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/th/T17380.stderr
- testsuite/tests/th/T18612.stderr
- + testsuite/tests/th/T27034.hs
- + testsuite/tests/th/T27034.stderr
- testsuite/tests/th/T8761.stderr
- testsuite/tests/th/all.T
- + 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/T16836d.hs
- + testsuite/tests/warnings/should_compile/T16836d.stderr
- testsuite/tests/warnings/should_compile/all.T
- utils/check-exact/ExactPrint.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/GhcUtils.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ef675ca483910d8360f51c2dbed2d4…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ef675ca483910d8360f51c2dbed2d4…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/9.14.2-rc2] 9 commits: Introduce UnitIndex for global external unit caching
by Zubin (@wz1000) 04 Sep '26
by Zubin (@wz1000) 04 Sep '26
04 Sep '26
Zubin pushed to branch wip/9.14.2-rc2 at Glasgow Haskell Compiler / GHC
Commits:
494d5744 by fendor at 2026-09-03T23:24:45+05:30
Introduce UnitIndex for global external unit caching
`UnitInfo`s have been observed to cause a lot of memory usage in #27500.
Especially with multiple home units, as the same (external) units are
processed from scratch, even though most of the time we end up with
exactly the same `UnitInfo`.
We introduce a `UnitEnv` global cache that allows us to store external
unit information that is used across all `HomeUnitEnv`s.
The most important change in this commit is the introduction of the `UnitIndex`.
It stores a global mapping of `UnitId` -> `UnitInfo`, and `initUnits`
always uses the cached `UnitInfo` entry to populate each
`HomeUnitEnv`'s `UnitState`.
This allows us to ensure the following property:
> Each `UnitInfo` should be alive exactly once in GHC.
All `UnitState`s should reference 'UnitInfo's stored in the 'UnitIndex'.
This ensured by calling 'initUnits' with the 'UnitIndex'.
In addition, the `ExternalUnitDatabases` may also hold a reference
to each on-disk representation of `UnitInfo`.
This means, we impose an hard upper bound on the number of `UnitInfo`s
alive in the GHC session:
> The number of alive `UnitInfo`s closure objects must be the
> sum of all loaded unit database times two.
We add performance regression tests that make sure the number of live
`UnitInfo` cannot exceed this threshold.
Closes #27500
-------------------------
Metric Decrease:
MultiComponentModules
MultiComponentModulesRecomp
MultiComponentModulesRecomp100
mhu-perf
LinkableUsage02
-------------------------
These metrics increases are especially notable, as we are not even
sharing anything big but merely the global package database with 50
entries.
It shows how careful sharing of `UnitInfo` can improve memory usage.
We expect this to be much more notable when the whole cabal package
database is shared across multiple home units.
`LinkableUsage02` metric decreases on unreg and i386 platform, only.
---
Technical details
To share the `UnitInfo`s correctly, it is important that we extract
the `WireMap` into the `UnitIndex`. At the moment of writing, `WireMap`
must be globally the same for all `HomeUnitEnv`s.
This is important, as we could otherwise not cache the "fully-resolved"
`UnitInfo`, as we don't change the `UnitId` or `unitAbiHash` when
resolving wired-in units. Thus, there could be ambiguities, when the
`WireMap` is not the same for all `UnitState`s across the `UnitEnv`.
We consider a `UnitInfo` fully-resolved, if wired-in units have been
updated, the `UnitInfo` has been validated and variables in the unit
config, such as `${pkgroot}` have been resolved.
Updating the wired-in units requires the `WireMap` to be globally the
same.
(cherry picked from commit 6cce494a7ec43953c7a949e0d8ce712abfe73da7)
- - - - -
81ff8fcf by fendor at 2026-09-03T23:24:45+05:30
Reuse the UnitIndexCache after initialising multiple home units
(cherry picked from commit 024c4d04a98f7e27b3dcb93f9b038f9b6b5a1ad9)
- - - - -
36a525b2 by Andreas Klebinger at 2026-09-03T23:24:45+05:30
Specialise: Stop looping on recursive dictionaries in interestingDict
interestingDict now doesn't look through loopbreaker unfoldings.
Doing so would cause infinite loops on certain dictionaries.
Fixes #27705.
(cherry picked from commit 578bd18509f0d2aeb004231a197f7f3898f86a2a)
- - - - -
10c01bb7 by Zubin Duggal at 2026-09-03T23:24:45+05:30
hadrian: constrain splitmix to keep building on Debian 9
- - - - -
2c0d4914 by Zubin Duggal at 2026-09-03T23:24:45+05:30
Bump file-io submodule to 0.1.6
- - - - -
8f2e7775 by Zubin Duggal at 2026-09-03T23:24:45+05:30
Bump haskeline submodule to 0.8.5.0
- - - - -
4c7174d7 by Zubin Duggal at 2026-09-03T23:24:45+05:30
Bump os-string submodule to 2.0.10
- - - - -
319278b9 by Zubin Duggal at 2026-09-03T23:24:45+05:30
Bump directory submodule to 1.3.11.0
- - - - -
65e02ee2 by Zubin Duggal at 2026-09-03T23:24:45+05:30
Prepare 9.14.2-rc2
- - - - -
62 changed files:
- − changelog.d/27626
- − changelog.d/27627
- − changelog.d/27703
- − changelog.d/27704
- − changelog.d/27717
- − changelog.d/T26423
- − changelog.d/T26716
- − changelog.d/T27202
- − changelog.d/T27308
- − changelog.d/T27440
- − changelog.d/T27455
- − changelog.d/T27583
- − changelog.d/T27586
- − changelog.d/T27639
- − changelog.d/T27657
- − changelog.d/arm_ncg_fixes_T27430
- − changelog.d/llvm-23
- compiler/GHC.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/Env.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Session/Units.hs
- compiler/GHC/Types/Unique.hs
- compiler/GHC/Unit/Env.hs
- compiler/GHC/Unit/External/Database.hs
- + compiler/GHC/Unit/External/Index.hs
- + compiler/GHC/Unit/External/ModuleOrigin.hs
- + compiler/GHC/Unit/External/Providers.hs
- + compiler/GHC/Unit/External/Query.hs
- + compiler/GHC/Unit/External/Substitution.hs
- + compiler/GHC/Unit/External/Validate.hs
- + compiler/GHC/Unit/External/Visibility.hs
- + compiler/GHC/Unit/External/Wired.hs
- compiler/GHC/Unit/Info.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Unit/Types.hs
- compiler/ghc.cabal.in
- docs/users_guide/9.14.2-notes.rst
- ghc/GHCi/UI.hs
- hadrian/cabal.project
- hadrian/src/Rules/Generate.hs
- libraries/base/changelog.md
- libraries/directory
- libraries/file-io
- libraries/haskeline
- libraries/os-string
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/driver/TUnitInfo/Foo.hs
- + testsuite/tests/driver/TUnitInfo/Makefile
- + testsuite/tests/driver/TUnitInfo/all.T
- + testsuite/tests/driver/TUnitInfo/genMhu.sh
- + testsuite/tests/driver/TUnitInfo/generic-unit-info-space-mhu.stdout
- + testsuite/tests/driver/TUnitInfo/generic-unit-info-space-single.stdout
- + testsuite/tests/driver/TUnitInfo/generic-unit-info-space.hs
- + testsuite/tests/driver/TUnitInfo/generic-unit-info-space.stdout
- + testsuite/tests/simplCore/should_run/T27705.hs
- + testsuite/tests/simplCore/should_run/T27705.stdout
- + testsuite/tests/simplCore/should_run/T27705_Inst.hs
- testsuite/tests/simplCore/should_run/all.T
- utils/haddock/haddock-api/src/Haddock.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/08f58e965838674e2a8260145b50e1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/08f58e965838674e2a8260145b50e1…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][master] simplifier: remove a bogus `assert` in `rebuild_app'` in `GHC.CoreToStg.Prep.cpeApp`.
by Marge Bot (@marge-bot) 04 Sep '26
by Marge Bot (@marge-bot) 04 Sep '26
04 Sep '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
6a44d591 by mangoiv at 2026-09-03T13:46:22-04:00
simplifier: remove a bogus `assert` in `rebuild_app'` in `GHC.CoreToStg.Prep.cpeApp`.
Prior to this commit
commit 08bc245be70d95801bc1138804ed1de9474fbdc0
Author: sheaf <sam.derbyshire(a)gmail.com>
Date: Sat Feb 28 16:30:43 2026 +0100
Clean up join points, casts & ticks
This commit shores up the logic dealing with casts and ticks occurring
in between a join point binding and a jump
any `PlaceRuntime` ticks we observed were profiling ticks, even though that
isn't necessary.
The more liberal rules in the above commit allow e.g. breakpoint ticks
(which are valid PlaceRuntime ticks) to legitimately appear in an argument
position.
Fixes #27556
- - - - -
6 changed files:
- + changelog.d/27556
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Types/Tickish.hs
- + testsuite/tests/simplCore/should_compile/T27556.hs
- + testsuite/tests/simplCore/should_compile/T27556.script
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
changelog.d/27556
=====================================
@@ -0,0 +1,5 @@
+section: compiler
+synopsis: Remove a too strict assert in coreprep; fixes a bug where debug builds
+ of GHC would fail to compile correctly optimized programs.
+mrs: !16558
+issues: #27556
=====================================
compiler/GHC/CoreToStg/Prep.hs
=====================================
@@ -1260,10 +1260,9 @@ cpeApp top_env expr
-- See Note [Ticks and mandatory eta expansion]
AITick tickish
- | tickishPlace tickish == PlaceRuntime
+ | PlaceRuntime <- tickishPlace tickish
, req_depth > 0
- -> assert (isProfTick tickish) $
- rebuild_app' env as fun' floats ss (tickish:rt_ticks) req_depth
+ -> rebuild_app' env as fun' floats ss (tickish:rt_ticks) req_depth
| otherwise
-- See [Floating Ticks in CorePrep]
-> rebuild_app' env as fun' (snocFloat floats (FloatTick tickish)) ss rt_ticks req_depth
=====================================
compiler/GHC/Types/Tickish.hs
=====================================
@@ -13,7 +13,6 @@ module GHC.Types.Tickish (
mkNoCount,
mkNoScope,
tickishIsCode,
- isProfTick,
TickishPlacement(..),
tickishPlace,
tickishContains,
@@ -545,10 +544,6 @@ tickishIsCode ProfNote{} = True
tickishIsCode Breakpoint{} = True
tickishIsCode HpcTick{} = True
-isProfTick :: GenTickish pass -> Bool
-isProfTick ProfNote{} = True
-isProfTick _ = False
-
-- | Governs the kind of expression that the tick gets placed on when
-- annotating for example using @mkTick@. If we find that we want to
-- put a tickish on an expression ruled out here, we try to float it
=====================================
testsuite/tests/simplCore/should_compile/T27556.hs
=====================================
@@ -0,0 +1,4 @@
+import Control.Exception
+
+main = mask $ \restore -> restore (pure ())
+
=====================================
testsuite/tests/simplCore/should_compile/T27556.script
=====================================
@@ -0,0 +1 @@
+:l T27556
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -611,3 +611,4 @@ test('T27296', [], makefile_test, ['T27296'])
test('T27296b', [], makefile_test, ['T27296b'])
test('T27589', [grep_errmsg(r'wombat')], compile, ['-O -ddump-simpl -dno-typeable-binds -dsuppress-uniques'])
test('T27590', [grep_errmsg(r'wombat')], compile, ['-O -ddump-simpl -dno-typeable-binds -dsuppress-uniques'])
+test('T27556', [only_ways('ghci'), extra_hc_opts('-O -fno-unoptimized-core-for-interpreter')], ghci_script, ['T27556.script'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/6a44d591804d46bfd6469e26836ffa3…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/6a44d591804d46bfd6469e26836ffa3…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][master] Add -Wimplicit-field-strictness (#16836)
by Marge Bot (@marge-bot) 04 Sep '26
by Marge Bot (@marge-bot) 04 Sep '26
04 Sep '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
9e7739ab by Simon Jakobi at 2026-09-03T13:45:43-04:00
Add -Wimplicit-field-strictness (#16836)
This opt-in warning fires when a data constructor field lacks an
explicit strictness annotation (`!` or `~`). It complements the
LazyFieldAnnotations extension (4762a8bf30f) from GHC proposal 752,
which makes `~` annotations available for this purpose.
Deciding which fields to report requires their levity, so the check
runs after typechecking. To keep the noise down, the diagnostic is
emitted once per data declaration, grouped by constructor.
Closes #16836.
Assisted-by: Claude Fable 5
- - - - -
20 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/T16836d.hs
- + testsuite/tests/warnings/should_compile/T16836d.stderr
- testsuite/tests/warnings/should_compile/all.T
Changes:
=====================================
changelog.d/implicit-field-strictness-warning
=====================================
@@ -0,0 +1,10 @@
+section: compiler
+synopsis: Add `-Wimplicit-field-strictness`
+issues: #16836
+mrs: !16555
+
+description: {
+ The new opt-in warning :ghc-flag:`-Wimplicit-field-strictness` reports
+ data constructor fields that lack an explicit strictness annotation
+ (``!`` or ``~``).
+}
=====================================
changelog.d/lazy-field-annotations
=====================================
@@ -11,4 +11,7 @@ description: {
continues to control the default strictness of unannotated fields.
See `GHC Proposal #752 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0752-l…>`_.
+
+ Also note the new opt-in :ghc-flag:`-Wimplicit-field-strictness` warning, which
+ reports fields lacking an explicit annotation.
}
=====================================
compiler/GHC/Driver/Flags.hs
=====================================
@@ -1142,6 +1142,7 @@ data WarningFlag =
| Opt_WarnUnrecognisedModifiers -- ^ @since 10.0
| Opt_WarnSemaphoreOpenFailure -- Since 10.0.1
| Opt_WarnDefaultedCallStack -- ^ @since 10.2
+ | Opt_WarnImplicitFieldStrictness -- ^ @since 10.2
deriving (Eq, Ord, Show, Enum, Bounded)
-- | Return the names of a WarningFlag
@@ -1251,6 +1252,7 @@ warnFlagNames wflag = case wflag of
Opt_WarnTypeEqualityRequiresOperators -> "type-equality-requires-operators" :| []
Opt_WarnMissingRoleAnnotations -> "missing-role-annotations" :| []
Opt_WarnImplicitRhsQuantification -> "implicit-rhs-quantification" :| []
+ Opt_WarnImplicitFieldStrictness -> "implicit-field-strictness" :| []
Opt_WarnIncompleteExportWarnings -> "incomplete-export-warnings" :| []
Opt_WarnIncompleteRecordSelectors -> "incomplete-record-selectors" :| []
Opt_WarnBadlyLevelledTypes -> "badly-levelled-types" :| []
=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -2449,6 +2449,7 @@ wWarningFlagsDeps = [minBound..maxBound] >>= \x -> case x of
Opt_WarnUnrecognisedModifiers -> warnSpec x
Opt_WarnSemaphoreOpenFailure -> warnSpec x
Opt_WarnDefaultedCallStack -> warnSpec x
+ Opt_WarnImplicitFieldStrictness -> warnSpec x
warningGroupsDeps :: [(Deprecation, FlagSpec WarningGroup)]
warningGroupsDeps = map mk warningGroups
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -1384,6 +1384,21 @@ instance Diagnostic TcRnMessage where
hang (text "Missing role annotation" <> colon)
2 (text "type role" <+> ppr name <+> hsep (map ppr roles))
+ TcRnImplicitFieldStrictness _lazy_anns cons -> mkSimpleDecorated $
+ hang (text "These constructor fields lack an explicit strictness annotation" <> colon)
+ 2 (vcat (map ppr_con (NE.toList cons)))
+ where
+ ppr_con (con, fields) =
+ bullet <+> text "In" <+> quotes (ppr con) <> colon <+> ppr_fields (NE.toList fields)
+ ppr_fields fields
+ | let names = [n | ImplicitStrictnessRecField n <- fields]
+ , not (null names)
+ = text "field" <> plural names <+> quotedListWithAnd (map ppr names)
+ | otherwise
+ = let poss = [i | ImplicitStrictnessPosField i <- fields]
+ in text "field" <> plural poss
+ <+> unquotedListWith (text "and") (map int poss)
+
TcRnIllformedTypePattern p
-> mkSimpleDecorated $
hang (text "Ill-formed type pattern:") 2 (ppr p)
@@ -2693,6 +2708,8 @@ instance Diagnostic TcRnMessage where
-> ErrorWithoutFlag
TcRnMissingRoleAnnotation{}
-> WarningWithFlag Opt_WarnMissingRoleAnnotations
+ TcRnImplicitFieldStrictness{}
+ -> WarningWithFlag Opt_WarnImplicitFieldStrictness
TcRnIllegalInvisTyVarBndr{}
-> ErrorWithoutFlag
TcRnIllegalWildcardTyVarBndr{}
@@ -3428,6 +3445,12 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnMissingRoleAnnotation{}
-> noHints
+ TcRnImplicitFieldStrictness lazy_anns _
+ -> SuggestExplicitFieldStrictness
+ : [ useExtensionInOrderTo
+ (text "to allow" <+> quotes (char '~') <+> text "annotations")
+ LangExt.LazyFieldAnnotations
+ | not lazy_anns ]
TcRnIllegalInvisTyVarBndr{}
-> [suggestExtension LangExt.TypeAbstractions]
TcRnIllegalWildcardTyVarBndr{}
=====================================
compiler/GHC/Tc/Errors/Types.hs
=====================================
@@ -123,6 +123,7 @@ module GHC.Tc.Errors.Types (
, TypeSyntax(..)
, typeSyntaxExtension
, SuggestLinear(..)
+ , ImplicitStrictnessField(..)
-- * Errors for hs-boot and signature files
, BadBootDecls(..)
@@ -4235,6 +4236,23 @@ data TcRnMessage where
-}
TcRnMissingRoleAnnotation :: Name -> [Role] -> TcRnMessage
+
+ {-| TcRnImplicitFieldStrictness is a warning that occurs when a data
+ constructor field lacks an explicit strictness annotation (@!@ or @~@)
+
+ Controlled by flags:
+ - Wimplicit-field-strictness
+
+ Test cases:
+ T16836a, T16836b, T16836c, T16836d
+
+ -}
+ TcRnImplicitFieldStrictness
+ :: Bool -- ^ whether @LazyFieldAnnotations@ is enabled
+ -> NonEmpty (Name, NonEmpty ImplicitStrictnessField)
+ -- ^ per data constructor, the fields lacking annotations
+ -> TcRnMessage
+
{-| TcRnPatersonCondFailure is an error that occurs when an instance
declaration fails to conform to the Paterson conditions. Which particular condition
fails depends on the constructor of PatersonCondFailure
@@ -6399,6 +6417,14 @@ data PatSynInvalidRhsReason
| PatSynUnboundVar !Name
deriving (Generic)
+-- | A constructor field lacking an explicit strictness annotation, as
+-- reported by 'TcRnImplicitFieldStrictness'.
+data ImplicitStrictnessField
+ -- | A record field
+ = ImplicitStrictnessRecField FieldLabelString
+ -- | A positional argument (1-based index)
+ | ImplicitStrictnessPosField Int
+
data BadFieldAnnotationReason where
{-| A lazy data type field annotation (~) was used without enabling the
extension LazyFieldAnnotations.
=====================================
compiler/GHC/Tc/TyCl.hs
=====================================
@@ -5022,6 +5022,16 @@ checkValidTyCon tc
; mapM_ (checkValidDataCon dflags ex_ok tc) data_cons
; mapM_ (checkPartialRecordField data_cons) (tyConFieldLabels tc)
+ ; warn_implicit_strictness <- woptM Opt_WarnImplicitFieldStrictness
+ ; when (warn_implicit_strictness
+ && not (isNewTyCon tc)
+ && not (isTypeDataTyCon tc)) $
+ whenIsJust (NE.nonEmpty (mapMaybe conImplicitStrictnessFields data_cons)) $
+ \offenders ->
+ do { lazy_anns <- xoptM LangExt.LazyFieldAnnotations
+ ; addDiagnosticTc $
+ TcRnImplicitFieldStrictness lazy_anns offenders }
+
-- Check that fields with the same name share a type
; mapM_ check_fields groups }}
where
@@ -5072,6 +5082,29 @@ checkValidTyCon tc
res2 = dataConOrigResTy con2
fty2 = dataConFieldType con2 lbl
+-- | For a given data constructor, collect the fields to report for
+-- @-Wimplicit-field-strictness@.
+--
+-- Only fields whose type is known to be lifted are collected: unlifted
+-- fields are unconditionally strict, and annotating one with @!@ or
+-- @~@ would trigger @-Wredundant-strictness-flags@.
+conImplicitStrictnessFields :: DataCon -> Maybe (Name, NonEmpty ImplicitStrictnessField)
+conImplicitStrictnessFields con
+ | Just ne_fields <- NE.nonEmpty fields
+ = Just (dataConName con, ne_fields)
+ | otherwise
+ = Nothing
+ where
+ fld_refs = case dataConFieldLabels con of
+ [] -> map ImplicitStrictnessPosField [1..]
+ lbls -> map (ImplicitStrictnessRecField . flLabel) lbls
+ fields = [ ref
+ | (ref, arg_ty, HsSrcBang _ _ NoSrcStrict)
+ <- zip3 fld_refs
+ (map scaledThing (dataConOrigArgTys con))
+ (dataConSrcBangs con)
+ , typeLevity_maybe arg_ty == Just Lifted ]
+
checkPartialRecordField :: [DataCon] -> FieldLabel -> TcM ()
-- Checks the partial record field selector, and warns.
-- See Note [Checking partial record field]
=====================================
compiler/GHC/Types/Error/Codes.hs
=====================================
@@ -542,6 +542,7 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnNegativeNumTypeLiteral" = 93632
GhcDiagnosticCode "TcRnUnusedQuantifiedTypeVar" = 54180
GhcDiagnosticCode "TcRnMissingRoleAnnotation" = 65490
+ GhcDiagnosticCode "TcRnImplicitFieldStrictness" = 47032
GhcDiagnosticCode "TcRnUntickedPromotedThing" = 49957
GhcDiagnosticCode "TcRnIllegalBuiltinSyntax" = 39716
=====================================
compiler/GHC/Types/Hint.hs
=====================================
@@ -343,6 +343,14 @@ data GhcHint
-}
| SuggestAddStandaloneKindSignature Name
+ {-| Suggests to annotate each constructor field with explicit strictness
+ (@!@ or @~@).
+
+ Triggered by: 'GHC.Tc.Errors.Types.TcRnImplicitFieldStrictness'
+ Test case(s): warnings/should_compile/T16836a
+ -}
+ | SuggestExplicitFieldStrictness
+
{-| Suggests the user to fill in the wildcard constraint to
disambiguate which constraint that is.
=====================================
compiler/GHC/Types/Hint/Ppr.hs
=====================================
@@ -185,6 +185,9 @@ instance Outputable GhcHint where
-> text "Use a standalone deriving declaration instead"
SuggestAddStandaloneKindSignature name
-> text "Add a standalone kind signature for" <+> quotes (ppr name)
+ SuggestExplicitFieldStrictness
+ -> text "Annotate each field with" <+> quotes (char '!')
+ <+> text "(strict) or" <+> quotes (char '~') <+> text "(lazy)"
SuggestFillInWildcardConstraint
-> text "Fill in the wildcard constraint yourself"
SuggestAppropriateTHTick ns
=====================================
docs/users_guide/exts/strict.rst
=====================================
@@ -194,6 +194,9 @@ The ``~`` annotation must be written in prefix form::
See `GHC Proposal #229 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-w…>`__
for the precise rules.
+See also :ghc-flag:`-Wimplicit-field-strictness`, which warns about
+fields lacking an explicit annotation.
+
.. _strict-data:
Strict-by-default data types
=====================================
docs/users_guide/using-warnings.rst
=====================================
@@ -2505,6 +2505,21 @@ of ``-W(no-)*``.
In other words the type-class role cannot be accidentally left
representational or phantom, which could affected the code correctness.
+.. ghc-flag:: -Wimplicit-field-strictness
+ :shortdesc: warn when constructor fields lack explicit strictness annotations
+ :type: dynamic
+ :reverse: -Wno-implicit-field-strictness
+ :category:
+
+ :since: 10.2.1
+ :default: off
+
+ .. index::
+ single: strictness annotations, missing
+
+ This warning reports data constructor fields that lack an explicit
+ strictness annotation (``!`` or ``~``).
+
.. ghc-flag:: -Wimplicit-rhs-quantification
:shortdesc: warn when type variables on the RHS of a type synonym are implicitly quantified
:type: dynamic
=====================================
testsuite/tests/warnings/should_compile/T16836a.hs
=====================================
@@ -0,0 +1,37 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+module T16836a where
+
+-- plain multi-constructor data
+-- warns for both constructors
+data T a = MkT a Bool
+ | MkT2 !Int a
+
+-- record with a shared field group
+-- warns for x, y and z; not for b
+data R = MkR { x, y :: Int, z :: Char, b :: !Bool }
+
+-- infix constructor
+-- warns for the first argument
+data I = Int :+: !Bool
+
+-- GADT syntax
+-- warns for the first argument
+data G a where
+ MkG :: Int -> !Bool -> G a
+
+-- GADT record syntax
+-- warns for gx
+data GR a where
+ MkGR :: { gx :: Int, gy :: !Bool } -> GR a
+
+-- data family instance
+-- warns
+data family F a
+data instance F Int = MkF Char
+
+-- fully annotated
+-- doesn't warn
+data S = MkS !Int !Bool
=====================================
testsuite/tests/warnings/should_compile/T16836a.stderr
=====================================
@@ -0,0 +1,55 @@
+T16836a.hs:9:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkT’: fields 1 and 2
+ • In ‘MkT2’: field 2
+ • In the data type declaration for ‘T’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:14:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkR’: fields ‘x’, ‘y’ and ‘z’
+ • In the data type declaration for ‘R’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:18:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘:+:’: field 1
+ • In the data type declaration for ‘I’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:22:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkG’: field 1
+ • In the data type declaration for ‘G’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:27:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkGR’: field ‘gx’
+ • In the data type declaration for ‘GR’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
+T16836a.hs:33:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkF’: field 1
+ • In the data family instance declaration for ‘F’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
=====================================
testsuite/tests/warnings/should_compile/T16836b.hs
=====================================
@@ -0,0 +1,25 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeData #-}
+{-# LANGUAGE EmptyDataDecls #-}
+{-# LANGUAGE LazyFieldAnnotations #-}
+module T16836b where
+
+-- fully annotated declarations don't warn
+data T a = MkT ~a !Bool
+data R = MkR { x, y :: !Int, z :: ~Char }
+data G a where
+ MkG :: !Int -> ~Bool -> G a
+data family F a
+data instance F Int = MkF !Char
+
+-- newtypes can't have annotations; exempt
+newtype N = MkN Int
+
+-- 'type data' can't have annotations; exempt
+type data TD = MkTD Bool
+
+-- no fields, nothing to annotate
+data E
+data Nullary = A | B
=====================================
testsuite/tests/warnings/should_compile/T16836c.hs
=====================================
@@ -0,0 +1,6 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE StrictData #-}
+module T16836c where
+
+-- unannotated fields warn under StrictData too
+data T a = MkT a !Bool ~Char
=====================================
testsuite/tests/warnings/should_compile/T16836c.stderr
=====================================
@@ -0,0 +1,6 @@
+T16836c.hs:6:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkT’: field 1
+ • In the data type declaration for ‘T’
+ Suggested fix: Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+
=====================================
testsuite/tests/warnings/should_compile/T16836d.hs
=====================================
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wimplicit-field-strictness #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedDatatypes #-}
+module T16836d where
+
+import GHC.Exts
+
+-- unlifted fields can't be usefully annotated; exempt
+data P = MkP Int# (# Int, Int #)
+
+type UD :: UnliftedType
+data UD = MkUD
+
+-- a field of an unlifted data type is exempt too
+data Q = MkQ UD
+
+-- mixed constructor
+-- warns only for the lifted field 2
+data M = MkM Int# Int
=====================================
testsuite/tests/warnings/should_compile/T16836d.stderr
=====================================
@@ -0,0 +1,9 @@
+T16836d.hs:20:1: warning: [GHC-47032] [-Wimplicit-field-strictness]
+ • These constructor fields lack an explicit strictness annotation:
+ • In ‘MkM’: field 2
+ • In the data type declaration for ‘M’
+ Suggested fixes:
+ • Annotate each field with ‘!’ (strict) or ‘~’ (lazy)
+ • Use the ‘LazyFieldAnnotations’ extension (implied by ‘StrictData’)
+ to allow ‘~’ annotations
+
=====================================
testsuite/tests/warnings/should_compile/all.T
=====================================
@@ -91,3 +91,7 @@ test('T25901_imp_unused_3', [extra_files(['T25901_helper_3.hs'])], multimod_comp
test('T25901_imp_unused_4', normal, compile, ['-Wunused-imports'])
test('T25901_imp_dodgy_1', [extra_files(['T25901_helper_1.hs'])], multimod_compile, ['T25901_imp_dodgy_1', '-v0 -Wdodgy-imports'])
test('T25901_imp_dodgy_2', [extra_files(['T25901_helper_2.hs'])], multimod_compile, ['T25901_imp_dodgy_2', '-v0 -Wdodgy-imports'])
+test('T16836a', normal, compile, [''])
+test('T16836b', normal, compile, [''])
+test('T16836c', normal, compile, [''])
+test('T16836d', normal, compile, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9e7739ab58eca17e87c4f949987a4e7…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9e7739ab58eca17e87c4f949987a4e7…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/romes/multi-threaded-debugger] ThreadBreaksIsolationMode
by Rodrigo Mesquita (@alt-romes) 04 Sep '26
by Rodrigo Mesquita (@alt-romes) 04 Sep '26
04 Sep '26
Rodrigo Mesquita pushed to branch wip/romes/multi-threaded-debugger at Glasgow Haskell Compiler / GHC
Commits:
9d82db82 by Rodrigo Mesquita at 2026-09-03T18:44:53+01:00
ThreadBreaksIsolationMode
- - - - -
4 changed files:
- compiler/GHC.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Eval/Types.hs
- ghc/GHCi/UI/Monad.hs
Changes:
=====================================
compiler/GHC.hs
=====================================
@@ -198,7 +198,7 @@ module GHC (
isStmt, hasImport, isImport, isDecl,
-- ** The debugger
- SingleStep(..),
+ SingleStep(..), ThreadBreaksIsolationMode(..),
Resume(..),
History(historyBreakpointId, historyEnclosingDecls),
GHC.getHistorySpan, getHistoryModule,
=====================================
compiler/GHC/Runtime/Eval.hs
=====================================
@@ -13,7 +13,7 @@ module GHC.Runtime.Eval (
Resume(..), History(..),
execStmt, execStmt', ExecOptions(..), execOptions, ExecResult(..), resumeExec,
runDecls, runDeclsWithLocation, runParsedDecls,
- parseImportDecl, SingleStep(..),
+ parseImportDecl, SingleStep(..), ThreadBreaksIsolationMode(..),
abandon, abandonAll,
getResumeContext,
getHistorySpan,
@@ -184,8 +184,8 @@ execOptions = ExecOptions
, execSourceFile = "<interactive>"
, execLineNumber = 1
, execWrap = EvalThis -- just run the statement, don't wrap it in anything
- , execIsolateBreaks = True
- -- by default we just care about breakpoints hit in this "main" thread
+ , execIsolateMode = SingleThreadedBreaks
+ -- by default we just care about breakpoints hit in this eval thread
}
-- | Run a statement in the current interactive context.
@@ -211,7 +211,7 @@ execStmt input exec_opts@ExecOptions{..} = do
-- doing preprocessing on the AST before execution, e.g. in GHCi (see
-- GHCi.UI.runStmt).
execStmt' :: GhcMonad m => GhciLStmt GhcPs -> String -> ExecOptions -> m ExecResult
-execStmt' stmt stmt_text opts@ExecOptions{..} = do
+execStmt' stmt stmt_text ExecOptions{..} = do
hsc_env <- getSession
let interp = hscInterp hsc_env
@@ -232,8 +232,8 @@ execStmt' stmt stmt_text opts@ExecOptions{..} = do
status <-
liftIO $ do
- let eval_opts = initEvalOpts idflags' (enableGhcStepMode execSingleStep)
- { isolateThreadBreaks = execIsolateThreadBreaks }
+ let eval_opts = (initEvalOpts idflags' (enableGhcStepMode execSingleStep))
+ { isolateThreadBreaks = enableIsolateThreadBreaks execIsolateMode }
evalStmt interp eval_opts (execWrap hval)
let ic = hsc_IC hsc_env
@@ -241,7 +241,7 @@ execStmt' stmt stmt_text opts@ExecOptions{..} = do
size = ghciHistSize idflags'
- handleRunStatus opts stmt_text bindings ids
+ handleRunStatus execSingleStep execIsolateMode stmt_text bindings ids
status (emptyHistory size)
runDecls :: GhcMonad m => String -> m [Name]
@@ -293,15 +293,15 @@ emptyHistory size = nilBL size
-- breakpoint if we don't care about that breakpoint (e.g. if using :steplocal
-- or :stepmodule, rather than :step, we only care about certain breakpoints).
handleRunStatus :: GhcMonad m
- => ExecOptions
+ => SingleStep
+ -> ThreadBreaksIsolationMode
-> String
-> ResumeBindings
-> [Id]
-> EvalStatus_ [ForeignHValue] [HValueRef]
-> BoundedList History
-> m ExecResult
-handleRunStatus ExecOptions{execSingleStep = step, execIsolateThreadBreaks}
- expr bindings final_ids status history0 = do
+handleRunStatus step isolateMode expr bindings final_ids status history0 = do
hsc_env <- getSession
let
interp = hscInterp hsc_env
@@ -395,22 +395,25 @@ handleRunStatus ExecOptions{execSingleStep = step, execIsolateThreadBreaks}
return (ExecBreak names (Just ibi))
else do
-- resume with the same step type
- let eval_opts = initEvalOpts dflags (enableGhcStepMode step)
- { isolateThreadBreaks = execIsolateThreadBreaks }
+ let eval_opts = (initEvalOpts dflags (enableGhcStepMode step))
+ { isolateThreadBreaks = enableIsolateThreadBreaks isolateMode }
status <- liftIO $ GHCi.resumeStmt interp eval_opts resume_ctxt_fhv
history <- if not tracing then pure history0 else do
history1 <- liftIO $ mkHistory hug apStack_fhv ibi
let !history' = history1 `consBL` history0
-- history is strict, otherwise our BoundedList is pointless.
return history'
- handleRunStatus step expr bindings final_ids status history
+ handleRunStatus step isolateMode expr bindings final_ids status history
where
tracing | RunAndLogSteps <- step = True
| otherwise = False
-resumeExec :: GhcMonad m => SingleStep -> Maybe Int
+resumeExec :: GhcMonad m
+ => SingleStep
+ -> ThreadBreaksIsolationMode
+ -> Maybe Int
-> m ExecResult
-resumeExec step mbCnt
+resumeExec step isolateMode mbCnt
= do
hsc_env <- getSession
let ic = hsc_IC hsc_env
@@ -455,7 +458,8 @@ resumeExec step mbCnt
(Just brkpt, Just cnt) -> setupBreakpoint interp brkpt cnt
_ -> return ()
- let eval_opts = initEvalOpts dflags (enableGhcStepMode step)
+ let eval_opts = (initEvalOpts dflags (enableGhcStepMode step))
+ { isolateThreadBreaks = enableIsolateThreadBreaks isolateMode }
status <- liftIO $ GHCi.resumeStmt interp eval_opts fhv
let prevHistoryLst = fromListBL 50 hist
hug = hsc_HUG hsc_env
@@ -466,7 +470,7 @@ resumeExec step mbCnt
hist1 <- liftIO (mkHistory hug apStack bi)
return $ hist1 `consBL` fromListBL 50 hist
| otherwise -> pure prevHistoryLst
- handleRunStatus step expr bindings final_ids status =<< hist'
+ handleRunStatus step isolateMode expr bindings final_ids status =<< hist'
setupBreakpoint :: GhcMonad m => Interp -> InternalBreakpointId -> Int -> m () -- #19157
setupBreakpoint interp ibi cnt = do
=====================================
compiler/GHC/Runtime/Eval/Types.hs
=====================================
@@ -10,6 +10,7 @@ module GHC.Runtime.Eval.Types (
Resume(..), ResumeBindings, IcGlobalRdrEnv(..),
History(..), ExecResult(..),
SingleStep(..), enableGhcStepMode, breakHere,
+ ThreadBreaksIsolationMode(..), enableIsolateThreadBreaks,
ExecOptions(..)
) where
@@ -36,7 +37,8 @@ data ExecOptions
, execSourceFile :: String -- ^ filename (for errors)
, execLineNumber :: Int -- ^ line number (for errors)
, execWrap :: ForeignHValue -> EvalExpr ForeignHValue
- , execIsolateThreadBreaks :: Bool -- ^ just like @'isolateThreadBreaks'@
+ , execIsolateMode :: ThreadBreaksIsolationMode
+ -- ^ like @'isolateThreadBreaks'@
}
-- | What kind of stepping are we doing?
@@ -65,6 +67,17 @@ data SingleStep
| ModuleStep
{ breakAt :: SrcSpan }
+-- | Just like @'isolateThreadBreaks'@, determining whether the
+-- execution/resuming execution of an expression should stop whenever any
+-- non-isolated thread hits a breakpoint, or only when the thread executing
+-- that expression specifically stops.
+data ThreadBreaksIsolationMode
+ -- | Stop exclusively on the breakpoints in this thread
+ = SingleThreadedBreaks
+ -- | Stop whenever any thread that is not running in 'SingleThreadedBreaks'
+ -- isolation mode hits a breakpoint
+ | MultiThreadedBreaks
+
-- | Whether this 'SingleStep' mode requires instructing the interpreter to
-- step at every breakpoint or after every return (see @'EvalStep'@).
enableGhcStepMode :: SingleStep -> EvalStep
@@ -73,6 +86,10 @@ enableGhcStepMode StepOut{} = EvalStepOut
-- for the remaining step modes we need to stop at every single breakpoint.
enableGhcStepMode _ = EvalStepSingle
+enableIsolateThreadBreaks :: ThreadBreaksIsolationMode -> Bool
+enableIsolateThreadBreaks SingleThreadedBreaks = True
+enableIsolateThreadBreaks MultiThreadedBreaks = False
+
-- | Given a 'SingleStep' mode, whether the breakpoint was explicitly active,
-- and the SrcSpan of a breakpoint we hit, return @True@ if we should stop at
-- this breakpoint.
=====================================
ghc/GHCi/UI/Monad.hs
=====================================
@@ -412,7 +412,7 @@ resume step mbIgnoreCnt = do
withProgName (progname st) $
withArgs (args st) $
reflectGHCi x $ do
- GHC.resumeExec step mbIgnoreCnt
+ GHC.resumeExec step GHC.SingleThreadedBreaks mbIgnoreCnt
-- --------------------------------------------------------------------------
-- timing & statistics
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9d82db8234bbbbe11096988b3210d85…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9d82db8234bbbbe11096988b3210d85…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0