| ... |
... |
@@ -25,6 +25,7 @@ import GHC.Unit |
|
25
|
25
|
import GHC.Core.Type
|
|
26
|
26
|
import GHC.Core.TyCon
|
|
27
|
27
|
import GHC.Core.InstEnv
|
|
|
28
|
+import GHC.Core.Class
|
|
28
|
29
|
|
|
29
|
30
|
import GHC.Data.Maybe
|
|
30
|
31
|
import GHC.Data.FastString
|
| ... |
... |
@@ -49,6 +50,7 @@ import GHC.Types.CostCentre.State |
|
49
|
50
|
import GHC.Types.Tickish
|
|
50
|
51
|
import GHC.Types.ProfAuto
|
|
51
|
52
|
import GHC.Tc.Types.ErrCtxt
|
|
|
53
|
+import GHC.Tc.Utils.TcType
|
|
52
|
54
|
|
|
53
|
55
|
import Control.Monad
|
|
54
|
56
|
import Data.List (isSuffixOf, intersperse)
|
| ... |
... |
@@ -57,6 +59,7 @@ import Data.Foldable (toList) |
|
57
|
59
|
import Trace.Hpc.Mix
|
|
58
|
60
|
|
|
59
|
61
|
import Data.Bifunctor (second)
|
|
|
62
|
+import Data.Functor
|
|
60
|
63
|
import Data.List.NonEmpty (NonEmpty (..))
|
|
61
|
64
|
import Data.Set (Set)
|
|
62
|
65
|
import qualified Data.Set as Set
|
| ... |
... |
@@ -101,12 +104,15 @@ addTicksToBinds |
|
101
|
104
|
-- isExportedId doesn't work yet (the desugarer
|
|
102
|
105
|
-- hasn't set it), so we have to work from this set.
|
|
103
|
106
|
-> [TyCon] -- ^ Type constructors in this module
|
|
104
|
|
- -> IdEnv DFunId
|
|
|
107
|
+ -> [ClsInst] -- ^ Class instances in this module
|
|
|
108
|
+ -> IdEnv DFunId -- ^ Mapping from class method Ids to the DFunIds
|
|
|
109
|
+ -- of the class instance they belong to. See Note
|
|
|
110
|
+ -- [Instance Method Coverage].
|
|
105
|
111
|
-> LHsBinds GhcTc
|
|
106
|
112
|
-> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick, SizedSeq Tick))
|
|
107
|
113
|
|
|
108
|
114
|
addTicksToBinds logger cfg
|
|
109
|
|
- mod mod_loc exports tyCons inst_meths binds
|
|
|
115
|
+ mod mod_loc exports tyCons insts inst_meths binds
|
|
110
|
116
|
| let passes = ticks_passes cfg
|
|
111
|
117
|
, not (null passes)
|
|
112
|
118
|
, Just orig_file <- ml_hs_file mod_loc = do
|
| ... |
... |
@@ -132,8 +138,12 @@ addTicksToBinds logger cfg |
|
132
|
138
|
, tickishType = tickish
|
|
133
|
139
|
, recSelBinds = emptyVarEnv
|
|
134
|
140
|
, instMeths = inst_meths
|
|
|
141
|
+ , instTicks = emptyVarEnv
|
|
135
|
142
|
}
|
|
136
|
|
- (binds',_,st') = unTM (addTickLHsBinds binds) env st
|
|
|
143
|
+ addTick = do
|
|
|
144
|
+ instTicks <- allocInstTicks insts
|
|
|
145
|
+ withEnv (\e -> e{ instTicks }) $ addTickLHsBinds binds
|
|
|
146
|
+ (binds',_,st') = unTM addTick env st
|
|
137
|
147
|
in (binds', st')
|
|
138
|
148
|
|
|
139
|
149
|
(binds1,st) = foldr tickPass (binds, initTTState) passes
|
| ... |
... |
@@ -315,9 +325,13 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches |
|
315
|
325
|
else
|
|
316
|
326
|
return Nothing
|
|
317
|
327
|
|
|
|
328
|
+ -- See Note [Instance Method Coverage].
|
|
|
329
|
+ instTick <- instMethTick id
|
|
|
330
|
+
|
|
318
|
331
|
let mbCons = maybe Prelude.id (:)
|
|
319
|
332
|
return $ L pos $ funBind { fun_matches = mg
|
|
320
|
|
- , fun_ext = second (tick `mbCons`) (fun_ext funBind) }
|
|
|
333
|
+ , fun_ext = second ((instTick `mbCons`) . (tick `mbCons`))
|
|
|
334
|
+ (fun_ext funBind) }
|
|
321
|
335
|
} }
|
|
322
|
336
|
where
|
|
323
|
337
|
-- See Note [Record-selector ticks]
|
| ... |
... |
@@ -366,6 +380,17 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches |
|
366
|
380
|
-- creating tick boxes for top-level bindings, we can then decide if a given
|
|
367
|
381
|
-- 'FunBind' corresponds to an inherited/generated instance method of a class
|
|
368
|
382
|
-- and skip creating the tick box for it.
|
|
|
383
|
+--
|
|
|
384
|
+-- Additionally, we also want to inform the user whether or not their class
|
|
|
385
|
+-- instance as a whole has been used at run-time. To do so, we create a single
|
|
|
386
|
+-- tick box at the instance head and tick that box when any method of that
|
|
|
387
|
+-- instance is evaluated.
|
|
|
388
|
+--
|
|
|
389
|
+-- As marker/tag-like class instances without any methods would always appear
|
|
|
390
|
+-- as uncovered using the above mechanism, we exclude them when creating
|
|
|
391
|
+-- instance tick boxes. This could potentially be improved in the future by
|
|
|
392
|
+-- tracking if any functions requiring an instance of an empty class have been
|
|
|
393
|
+-- evaluated.
|
|
369
|
394
|
|
|
370
|
395
|
-- TODO: Revisit this
|
|
371
|
396
|
addTickLHsBind (L pos (pat@(PatBind { pat_lhs = lhs
|
| ... |
... |
@@ -1128,6 +1153,7 @@ data TickTransEnv = TTE { fileName :: FastString |
|
1128
|
1153
|
, tickishType :: TickishType
|
|
1129
|
1154
|
, recSelBinds :: IdEnv DVarSet
|
|
1130
|
1155
|
, instMeths :: IdEnv DFunId
|
|
|
1156
|
+ , instTicks :: IdEnv CoreTickish
|
|
1131
|
1157
|
}
|
|
1132
|
1158
|
|
|
1133
|
1159
|
-- deriving Show
|
| ... |
... |
@@ -1268,6 +1294,21 @@ isBlackListed (RealSrcSpan pos _) = TM $ \ env st -> (Set.member pos (blackList |
|
1268
|
1294
|
isBlackListed GeneratedSrcSpan{} = return False
|
|
1269
|
1295
|
isBlackListed UnhelpfulSpan{} = return False
|
|
1270
|
1296
|
|
|
|
1297
|
+-- See Note [Instance Method Coverage].
|
|
|
1298
|
+allocInstTicks :: [ClsInst] -> TM (IdEnv CoreTickish)
|
|
|
1299
|
+allocInstTicks insts =
|
|
|
1300
|
+ ifDensity TickForCoverage (mkVarEnv . catMaybes <$> mapM alloc insts) (pure emptyVarEnv)
|
|
|
1301
|
+ where
|
|
|
1302
|
+ alloc ClsInst{ is_dfun, is_cls }
|
|
|
1303
|
+ | null (classMethods is_cls) = pure Nothing
|
|
|
1304
|
+ | otherwise = fmap (is_dfun,) <$> allocATickBox (TopLevelBox [s])
|
|
|
1305
|
+ False True (getSrcSpan is_dfun) noFVs
|
|
|
1306
|
+ where s = showSDocOneLine defaultSDocContext (pprSigmaType (idType is_dfun))
|
|
|
1307
|
+
|
|
|
1308
|
+-- See Note [Instance Method Coverage].
|
|
|
1309
|
+instMethTick :: Id -> TM (Maybe CoreTickish)
|
|
|
1310
|
+instMethTick id = getEnv <&> \e -> lookupVarEnv (instMeths e) id >>= lookupVarEnv (instTicks e)
|
|
|
1311
|
+
|
|
1271
|
1312
|
-- the tick application inherits the source position of its
|
|
1272
|
1313
|
-- expression argument to support nested box allocations
|
|
1273
|
1314
|
allocTickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> TM (HsExpr GhcTc)
|