[Git][ghc/ghc][wip/rafl/hpc-instances] hpc: Improve coverage semantics for instance methods and instances
Florian Ragwitz pushed to branch wip/rafl/hpc-instances at Glasgow Haskell Compiler / GHC Commits: 80aca549 by Florian Ragwitz at 2026-10-11T17:08:42-07:00 hpc: Improve coverage semantics for instance methods and instances Users care about which of their explicitly 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. We therefore skip generating top-level boxes for inherited methods which will appear as uncovered with no clear indication as to why, and no way to fix other than exercising code the user has not written. Previously, top-level boxes for those inherited methods would use the instance head as their source span. Now that those boxes are gone, we can use that source span for another purpose: We introduce a new top-level box for each class instance with its instance head as the source span, and use that to indicate whether or not an instance has been covered at all. We do this by making any method of the instance, inherited/generated or otherwise, tick the box for the instance head. Excluded from this are methodless classes, which could never be covered using the current mechanism. This could be improved upon further. These changes apply to ticking for program coverage only, and don't affect source notes. Additionally, we update the scope of record selector ticking to be limited to program coverage as well, as the oversight to also extend it to source notes has previously caused bugs and because record selector ticking is coverage-specific. Fixes #17155, #15932. - - - - - 12 changed files: - + changelog.d/hpc-classinsts - compiler/GHC/Core/Opt/Specialise.hs - compiler/GHC/CoreToIface.hs - compiler/GHC/HsToCore.hs - compiler/GHC/HsToCore/Ticks.hs - compiler/GHC/Tc/TyCl/Instance.hs - compiler/GHC/Types/Id/Info.hs - + testsuite/tests/hpc/instmeths/instmeths.hs - + testsuite/tests/hpc/instmeths/instmeths.stdout - + testsuite/tests/hpc/instmeths/test.T - testsuite/tests/simplCore/should_compile/T22375.stderr - testsuite/tests/simplCore/should_compile/T22375DataFamily.stderr Changes: ===================================== changelog.d/hpc-classinsts ===================================== @@ -0,0 +1,23 @@ +section: compiler +synopsis: Improve coverage reporting for class instances and their methods +description: + + Coverage reporting (:ghc-flag:`-fhpc`) now treats class instances more + naturally. + + Compiler-generated instance methods, such as inherited default methods, no + longer receive separate top-level coverage boxes. Explicitly implemented + instance methods retain their own declaration coverage. + + This means that it is no longer necessary to exercise all of a class' methods + in order for it to appear "covered". + + Additionally, top-level coverage boxes are now created for all instances of + classes with methods, and ticked by the use of *any* of the class' methods. + This indicates that an instance was in fact used at run-time. + + Note that classes without any instance methods are currently excluded from + this, and won't have any coverage boxes created. + +mrs: !16632 +issues: #17155 #15932 ===================================== compiler/GHC/Core/Opt/Specialise.hs ===================================== @@ -3082,6 +3082,7 @@ wantCallsFor _env f JoinId {} -> True WorkerLikeId {} -> True RepPolyId {} -> True + InstMethId {} -> True interestingDict :: SpecEnv -> CoreExpr -> Bool -- This is a subtle and important function ===================================== compiler/GHC/CoreToIface.hs ===================================== @@ -454,6 +454,7 @@ toIfaceTopBndr id toIfaceIdDetails :: Name -- ^ for trace/panic messages only -> IdDetails -> IfaceIdDetails toIfaceIdDetails _ VanillaId = IfVanillaId +toIfaceIdDetails _ (InstMethId {}) = IfVanillaId toIfaceIdDetails _ (WorkerLikeId dmds) = IfWorkerLikeId dmds toIfaceIdDetails _ (DFunId {}) = IfDFunId toIfaceIdDetails _ (RecSelId { sel_naughty = n ===================================== compiler/GHC/HsToCore.hs ===================================== @@ -170,7 +170,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 binds else return (binds, Nothing) ; let modBreaks | Just (_, _, breakpointSpecs) <- m_tickInfo ===================================== compiler/GHC/HsToCore/Ticks.hs ===================================== @@ -1,11 +1,11 @@ -{-# LANGUAGE NondecreasingIndentation, DataKinds #-} +{-# LANGUAGE NondecreasingIndentation, DataKinds, ViewPatterns #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {- (c) Galois, 2006 (c) University of Glasgow, 2007 -(c) Florian Ragwitz, 2025 +(c) Florian Ragwitz, 2025-2026 -} module GHC.HsToCore.Ticks @@ -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 @@ -43,6 +45,7 @@ import GHC.Types.Var.Set import GHC.Types.Var.Env import GHC.Types.Name.Set import GHC.Types.Name +import GHC.Types.Name.Env import GHC.Types.CostCentre import GHC.Types.CostCentre.State import GHC.Types.Tickish @@ -56,6 +59,7 @@ import Data.Foldable (toList) import Trace.Hpc.Mix import Data.Bifunctor (second) +import Data.Functor import Data.List.NonEmpty (NonEmpty (..)) import Data.Set (Set) import qualified Data.Set as Set @@ -100,11 +104,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 + -> [ClsInst] -- ^ Class instances in this module -> 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 binds | let passes = ticks_passes cfg , not (null passes) , Just orig_file <- ml_hs_file mod_loc = do @@ -129,8 +134,13 @@ addTicksToBinds logger cfg , this_mod = mod , tickishType = tickish , recSelBinds = emptyVarEnv + , instMeths = emptyVarEnv + , instTicks = emptyNameEnv } - (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 +241,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 +269,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 <- [instMeth abe_poly] ] } + where instMeth (idDetails -> InstMethId dfun) = Just dfun + instMeth id = lookupVarEnv (instMeths env) id + 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,16 +311,28 @@ 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 + -- See Note [Instance Method Coverage]. + -- We only exclude generated instance methods for now, not generated code in + -- general, whose coverage semantics may need to be considered separately. + let generatedInstMeth = tickishType env == HpcTicks + && 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 return Nothing + -- See Note [Instance Method Coverage]. + instTick <- instMethTick id + 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] @@ -338,6 +367,30 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches -- This scheme could be extended further in the future, making coverage for -- positional constructor fields mean that the field was accessed at run-time. +-- Note [Instance Method Coverage] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- Users expect source-level semantics for coverage reports (see #17155, +-- #15932). That is, code they've written themselves should be marked as covered +-- iff it is evaluated at run-time. Given that the implementation of class +-- instances creates top-level bindings for all methods of an instance, +-- inherited and hand-written, we need to go out of our way to create top-level +-- tick boxes only for methods which correspond to user-written code. +-- +-- Instance method 'Id's carry the name of the 'DFunId' of the instance they +-- belong to. When creating tick boxes for top-level bindings, we can use this +-- information to skip creating boxes for inherited/generated instance methods. +-- +-- Additionally, we also want to inform the user whether or not their class +-- instance as a whole has been used at run-time. To do so, we create a single +-- tick box at the instance head and tick that box when any method of that +-- instance is evaluated. +-- +-- As marker/tag-like class instances without any methods would always appear +-- as uncovered using the above mechanism, we exclude them when creating +-- instance tick boxes. This could potentially be improved in the future by +-- tracking if any functions requiring an instance of an empty class have been +-- evaluated. + -- TODO: Revisit this addTickLHsBind (L pos (pat@(PatBind { pat_lhs = lhs , pat_rhs = rhs @@ -1098,6 +1151,8 @@ data TickTransEnv = TTE { fileName :: FastString , this_mod :: Module , tickishType :: TickishType , recSelBinds :: IdEnv DVarSet + , instMeths :: IdEnv Name + , instTicks :: NameEnv CoreTickish } -- deriving Show @@ -1182,6 +1237,9 @@ getDensity = TM $ \env st -> (density env, noFVs, st) ifDensity :: TickDensity -> TM a -> TM a -> TM a ifDensity d th el = do d0 <- getDensity; if d == d0 then th else el +ifTickish :: TickishType -> TM a -> TM a -> TM a +ifTickish want th el = tickishType <$> getEnv >>= \got -> if want == got then th else el + getFreeVars :: TM a -> TM (FreeVars, a) getFreeVars (TM m) = TM $ \ env st -> case m env st of (a, fv, st') -> ((fv,a), fv, st') @@ -1238,6 +1296,20 @@ isBlackListed (RealSrcSpan pos _) = TM $ \ env st -> (Set.member pos (blackList isBlackListed GeneratedSrcSpan{} = return False isBlackListed UnhelpfulSpan{} = return False +-- See Note [Instance Method Coverage]. +allocInstTicks :: [ClsInst] -> TM (NameEnv CoreTickish) +allocInstTicks insts = + ifTickish HpcTicks (mkNameEnv . catMaybes <$> mapM alloc insts) (pure emptyNameEnv) + where + alloc ClsInst{ is_dfun, is_cls } + | null (classMethods is_cls) = pure Nothing + | otherwise = fmap (idName is_dfun,) <$> allocATickBox (TopLevelBox [getOccString is_dfun]) + False True (getSrcSpan is_dfun) noFVs + +-- See Note [Instance Method Coverage]. +instMethTick :: Id -> TM (Maybe CoreTickish) +instMethTick id = getEnv <&> \e -> lookupVarEnv (instMeths e) id >>= lookupNameEnv (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) @@ -1256,7 +1328,7 @@ allocTickBox boxLabel countEntries topOnly pos m return (this_loc (XExpr $ HsTick tickish $ this_loc e)) recSelTick :: Id -> TM (Maybe [CoreTickish]) -recSelTick id = ifDensity TickForCoverage maybe_tick (pure Nothing) +recSelTick id = ifTickish HpcTicks maybe_tick (pure Nothing) where maybe_tick = getEnv >>= maybe (pure Nothing) tick_all . (`lookupVarEnv` id) . recSelBinds ===================================== compiler/GHC/Tc/TyCl/Instance.hs ===================================== @@ -59,7 +59,7 @@ import GHC.Core.FamInstEnv import GHC.Core.Type import GHC.Core.Multiplicity import GHC.Core.InstEnv -import GHC.Core.Predicate( classMethodInstTy ) +import GHC.Core.Predicate( classMethodInstTy, isCoVarType ) import GHC.Core.TyCon import GHC.Core.Coercion.Axiom import GHC.Core.DataCon @@ -72,6 +72,7 @@ import GHC.Types.Var.Set import GHC.Types.Basic import GHC.Types.ForeignCall ( typeCheckCType ) import GHC.Types.Id +import GHC.Types.Id.Info import GHC.Types.InlinePragma import GHC.Types.SourceFile import GHC.Types.SourceText @@ -1859,7 +1860,7 @@ tcMethods _skol_info dfun_id clas tyvars dfun_ev_vars inst_tys tc_item :: ClassOpItem -> TcM (Id, LHsBind GhcTc, Maybe Implication) tc_item (sel_id, dm_info) | Just (user_bind, bndr_loc, prags) <- findMethodBind (idName sel_id) binds prag_fn - = tcMethodBody False clas tyvars dfun_ev_vars inst_tys + = tcMethodBody False dfun_id clas tyvars dfun_ev_vars inst_tys dfun_ev_binds is_derived hs_sig_fn spec_inst_prags prags sel_id user_bind bndr_loc @@ -1879,7 +1880,7 @@ tcMethods _skol_info dfun_id clas tyvars dfun_ev_vars inst_tys -- See Note [Implementation of Unsatisfiable constraints], -- in GHC.Tc.Errors, point (D). _ | (theta_id,unsat_msg) : _ <- unsat_thetas - -> do { (meth_id, _) <- mkMethIds clas tyvars dfun_ev_vars + -> do { (meth_id, _) <- mkMethIds dfun_id clas tyvars dfun_ev_vars inst_tys sel_id ; unsat_id <- tcLookupKnownKeyId unsatisfiableIdKey -- Recall that unsatisfiable :: forall {rep} (msg :: ErrorMessage) (a :: TYPE rep). Unsatisfiable msg => a @@ -1896,7 +1897,7 @@ tcMethods _skol_info dfun_id clas tyvars dfun_ev_vars inst_tys Just (dm_name, dm_spec) -> do { (meth_bind, inline_prags) <- mkDefMethBind inst_loc dfun_id clas sel_id dm_name dm_spec ; tcMethodBody (is_vanilla_dm dm_spec) - clas tyvars dfun_ev_vars inst_tys + dfun_id clas tyvars dfun_ev_vars inst_tys dfun_ev_binds is_derived hs_sig_fn spec_inst_prags inline_prags sel_id meth_bind inst_loc } @@ -1904,7 +1905,7 @@ tcMethods _skol_info dfun_id clas tyvars dfun_ev_vars inst_tys -- No default method Nothing -> do { traceTc "tc_def: warn" (ppr sel_id) - ; (meth_id, _) <- mkMethIds clas tyvars dfun_ev_vars + ; (meth_id, _) <- mkMethIds dfun_id clas tyvars dfun_ev_vars inst_tys sel_id ; dflags <- getDynFlags -- Add a binding whose RHS is an error @@ -2030,13 +2031,13 @@ Instead, we take the following approach: tcMethodBody :: Bool -- True <=> This is a vanilla default method -- See (TRC5) in Note [Tracking needed EvIds] -- in GHC.Tc.Solver.Solve - -> Class -> [TcTyVar] -> [EvVar] -> [TcType] + -> DFunId -> Class -> [TcTyVar] -> [EvVar] -> [TcType] -> TcEvBinds -> Bool -> HsSigFun -> [LTcSpecPrag] -> [LSig GhcRn] -> Id -> LHsBind GhcRn -> SrcSpan -> TcM (TcId, LHsBind GhcTc, Maybe Implication) -tcMethodBody is_vanilla_dm clas tyvars dfun_ev_vars inst_tys +tcMethodBody is_vanilla_dm dfun_id clas tyvars dfun_ev_vars inst_tys dfun_ev_binds is_derived sig_fn spec_inst_prags prags sel_id (L bind_loc meth_bind) bndr_loc @@ -2044,7 +2045,7 @@ tcMethodBody is_vanilla_dm clas tyvars dfun_ev_vars inst_tys do { traceTc "tcMethodBody" (ppr sel_id <+> ppr (idType sel_id) $$ ppr bndr_loc) ; let skol_info = MethSkol meth_name is_vanilla_dm ; (global_meth_id, local_meth_id) <- setSrcSpan bndr_loc $ - mkMethIds clas tyvars dfun_ev_vars + mkMethIds dfun_id clas tyvars dfun_ev_vars inst_tys sel_id ; let lm_bind = meth_bind { fun_id = L (noAnnSrcSpan bndr_loc) @@ -2162,16 +2163,19 @@ tcMethodBodyHelp hs_sig_fn sel_id local_meth_id meth_bind -- they are all for meth_id ------------------------ -mkMethIds :: Class -> [TcTyVar] -> [EvVar] +mkMethIds :: DFunId -> Class -> [TcTyVar] -> [EvVar] -> [TcType] -> Id -> TcM (TcId, TcId) -- returns (poly_id, local_id), but ignoring any instance signature -- See Note [Instance method signatures] -mkMethIds clas tyvars dfun_ev_vars inst_tys sel_id +mkMethIds dfun_id clas tyvars dfun_ev_vars inst_tys sel_id = do { poly_meth_name <- newName (mkClassOpAuxOcc sel_occ) ; local_meth_name <- newName sel_occ -- Base the local_meth_name on the selector name, because -- type errors from tcMethodBody come from here - ; let poly_meth_id = mkLocalId poly_meth_name ManyTy poly_meth_ty + ; let poly_meth_id = + assert (not (isCoVarType poly_meth_ty)) $ + Var.mkLocalVar (InstMethId (idName dfun_id)) + poly_meth_name ManyTy poly_meth_ty vanillaIdInfo local_meth_id = mkLocalId local_meth_name ManyTy local_meth_ty ; return (poly_meth_id, local_meth_id) } ===================================== compiler/GHC/Types/Id/Info.hs ===================================== @@ -222,6 +222,10 @@ data IdDetails -- - the [CbvMark] is always empty (and ignored) until after Tidy -- for ids from the current module -- - If non-empty, at least is isMarkedCbbv; see (CBV2) + | InstMethId + -- ^ An instance method. + Name + -- ^ 'Name' of the dictionary function the instance method belongs to. data RecSelInfo = RSI { rsi_def :: [ConLike] -- Record selector defined for these @@ -449,6 +453,7 @@ pprIdDetails other = brackets (pp other) ppWhen is_naughty (text "(naughty)") pp CoVarId = text "CoVarId" pp (JoinId arity marks) = text "JoinId" <> parens (int arity) <> parens (ppr marks) + pp (InstMethId name) = text "InstMethId" <> parens (ppr name) {- ************************************************************************ ===================================== testsuite/tests/hpc/instmeths/instmeths.hs ===================================== @@ -0,0 +1,57 @@ +import Data.List +import Data.Maybe +import Trace.Hpc.Mix +import Trace.Hpc.Reflect +import Trace.Hpc.Tix +import Trace.Hpc.Util + +class Foo a where + defMeth, defMeth', reqMeth :: a -> String + defMeth = const "class default" + defMeth' = const "class default" + +newtype T a = T a deriving (Show, Eq, Functor) +instance Foo (T a) where + reqMeth = const "Foo (T a) instance" + +newtype T' a = T' a + +instance Foo (T' a) where + reqMeth = const "Foo (T' a) instance" + defMeth = const "Foo (T' a) instance" + +-- no method use could "cover" this instance, so we (for now) omit the top-level box for it +class Marker a +instance Marker (T Bool) + +interesting :: (Int, MixEntry) -> Maybe (Int, HpcPos, String) +interesting (n, (pos, TopLevelBox [name])) | isInteresting name = Just (n, pos, name) + where isInteresting = (||) <$> isInst <*> isMeth + isInst = ("$f" `isPrefixOf`) + isMeth = (||) <$> (`elem` ["(==)", "(/=)", "show", "showList", "showsPrec", "fmap", "(<$)"]) + <*> ("Meth" `isInfixOf`) +interesting _ = Nothing + +-- candidate for HPC.Utils, maybe? +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 + print (T 23 == (succ <$> T 22)) -- tick Eq and Functor by using any of their methods + print (reqMeth (T' 1)) -- tick `Foo (T' a)` and that instance's `reqMeth` + + 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) <- sortOn (\(_, l, p) -> (p, l)) boxes ] ===================================== testsuite/tests/hpc/instmeths/instmeths.stdout ===================================== @@ -0,0 +1,12 @@ +True +"Foo (T' a) instance" +(1,"$fEqT","Eq") +(0,"$fFooT","Foo (T a)") +(1,"$fFooT'","Foo (T' a)") +(1,"$fFunctorT","Functor") +(0,"$fShowT","Show") +(0,"defMeth","defMeth = const \"class default\"") +(0,"defMeth","defMeth = const \"Foo (T' a) instance\"") +(0,"defMeth'","defMeth' = const \"class default\"") +(0,"reqMeth","reqMeth = const \"Foo (T a) instance\"") +(1,"reqMeth","reqMeth = const \"Foo (T' a) instance\"") ===================================== 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']) ===================================== testsuite/tests/simplCore/should_compile/T22375.stderr ===================================== @@ -5,7 +5,7 @@ Result size of Tidy Core -- RHS size: {terms: 14, types: 9, coercions: 0, joins: 0/0} T22375.$fEqX_$c== :: X -> X -> Bool -[GblId, +[GblId[InstMethId(T22375.$fEqX)], Arity=2, Str=<SL><SL>, Unf=Unf{Src=<vanilla>, TopLvl=True, @@ -27,7 +27,7 @@ T22375.$fEqX_$c== -- RHS size: {terms: 18, types: 9, coercions: 0, joins: 0/0} T22375.$fEqX_$c/= [InlPrag=INLINE (sat-args=2)] :: X -> X -> Bool -[GblId, +[GblId[InstMethId(T22375.$fEqX)], Arity=2, Str=<SL><SL>, Unf=Unf{Src=StableUser, TopLvl=True, ===================================== testsuite/tests/simplCore/should_compile/T22375DataFamily.stderr ===================================== @@ -5,7 +5,7 @@ Result size of Tidy Core -- RHS size: {terms: 14, types: 11, coercions: 2, joins: 0/0} T22375DataFamily.$fEqX_$c== :: X () -> X () -> Bool -[GblId, +[GblId[InstMethId(T22375DataFamily.$fEqX)], Arity=2, Str=<SL><SL>, Unf=Unf{Src=<vanilla>, TopLvl=True, @@ -36,7 +36,7 @@ T22375DataFamily.$fEqX_$c== -- RHS size: {terms: 18, types: 11, coercions: 2, joins: 0/0} T22375DataFamily.$fEqX_$c/= [InlPrag=INLINE (sat-args=2)] :: X () -> X () -> Bool -[GblId, +[GblId[InstMethId(T22375DataFamily.$fEqX)], Arity=2, Str=<SL><SL>, Unf=Unf{Src=StableUser, TopLvl=True, View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/80aca54961b995ce453eade7a872df6e... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/80aca54961b995ce453eade7a872df6e... 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
participants (1)
-
Florian Ragwitz (@rafl)