@@ -42,6 +42,7 @@ import Data.Dynamic (Dynamic, fromDynamic)
42
42
import Data.Function (on )
43
43
import Data.IORef (IORef , newIORef , readIORef )
44
44
import Data.List (groupBy , intercalate , nub , partition , stripPrefix )
45
+ import Data.Map (Map )
45
46
import qualified Data.Map as Map
46
47
import Data.Maybe (catMaybes , isJust , isNothing , mapMaybe )
47
48
import Data.Set (Set )
@@ -649,44 +650,6 @@ moduleToProb baseCC@CompConf {tempDirBase = baseTempDir, ..} mod_path mb_target
649
650
-- _ -> int_prob
650
651
return (cc', tc_modul, int_prob)
651
652
652
- -- Create a fake base loc for a trace.
653
- fakeBaseLoc :: CompileConfig -> EProblem -> EProgFix -> Ghc SrcSpan
654
- fakeBaseLoc cc prob (fix : _) = getLoc . head <$> buildTraceCorrelExpr cc prob fix
655
- fakeBaseLoc cc prob [] = error " Cannot construct base loc for empty prog!"
656
-
657
- -- When we do the trace, we use a "fake_target" function. This build the
658
- -- corresponding expression,
659
- buildTraceCorrelExpr :: CompileConfig -> EProblem -> EExpr -> Ghc [LHsExpr GhcPs ]
660
- buildTraceCorrelExpr cc EProb {.. } expr = do
661
- let correl =
662
- map (\ (nm, _, _) -> baseFun (mkVarUnqual $ fsLit $ " fake_target_" ++ rdrNamePrint nm) expr) e_prog
663
- correl_ctxts :: [LHsLocalBinds GhcPs ]
664
- correl_ctxts = map (\ c -> noLoc $ HsValBinds NoExtField (ValBinds NoExtField (unitBag c) [] )) correl
665
- correl_exprs :: [LHsExpr GhcPs ]
666
- correl_exprs = map (\ ctxt -> noLoc $ HsLet NoExtField ctxt (noLoc hole)) correl_ctxts
667
-
668
- pcorrels <- mapM (parseExprNoInit . showUnsafe) correl_exprs
669
- let getBod (L _ (HsLet _ (L _ (HsValBinds _ (ValBinds _ bg _))) _))
670
- | [L _ FunBind {fun_matches = MG {mg_alts = (L _ alts)}}] <- bagToList bg,
671
- [L _ Match {m_grhss = GRHSs {grhssGRHSs = [L _ (GRHS _ _ bod)]}}] <- alts =
672
- Just bod
673
- getBod _ = Nothing
674
- return $ mapMaybe getBod pcorrels
675
- buildTraceCorrelExpr _ _ _ = error " External fixes not supported!"
676
-
677
- -- We build a Map from the traced expression and to the original so we can
678
- -- correlate the trace information with the expression we're checking.
679
- -- This helps e.g. to find placements of changed elements (in our fixes) to the original position.
680
- buildTraceCorrel :: CompileConfig -> EProblem -> EExpr -> Ghc [Map. Map SrcSpan SrcSpan ]
681
- buildTraceCorrel cc prob expr = do
682
- map toCorrel <$> buildTraceCorrelExpr cc prob expr
683
- where
684
- expr_exprs = flattenExpr expr
685
- toCorrel trace_expr = Map. fromList $ filter (\ (e, b) -> isGoodSrcSpan e && isGoodSrcSpan b) locPairs
686
- where
687
- trace_exprs = flattenExpr trace_expr
688
- locPairs = zipWith (\ t e -> (getLoc t, getLoc e)) trace_exprs expr_exprs
689
-
690
653
-- | Runs a GHC action and cleans up any hpc-directories that might have been
691
654
-- created as a side-effect.
692
655
-- TODO: Does this slow things down massively? We lose out on the pre-generated
@@ -762,12 +725,22 @@ traceTarget ::
762
725
EProp ->
763
726
[RExpr ] ->
764
727
IO (Maybe TraceRes )
765
- traceTarget cc tp e fp ce = head <$> ( traceTargets cc tp e [(fp, ce)])
728
+ traceTarget cc tp e fp ce = head <$> traceTargets cc tp e [(fp, ce)]
766
729
767
- toInvokes :: Trace -> Map. Map SrcSpan Integer
768
- toInvokes res = Map. fromList $ map only_max $ flatten res
730
+ toInvokes :: Trace -> Map. Map ( EExpr , SrcSpan ) Integer
731
+ toInvokes (ex, res) = Map. fromList $ mapMaybe only_max $ flatten res
769
732
where
770
- only_max (src, r) = (mkInteractive src, maximum $ map snd r)
733
+ isOkBox (ExpBox _, _) = True
734
+ isOkBox _ = False
735
+ only_max :: (SrcSpan , [(BoxLabel , Integer )]) -> Maybe ((EExpr , SrcSpan ), Integer )
736
+ only_max (src, [] ) = Just ((ex, src), 0 )
737
+ only_max (src, [x]) | isOkBox x = Just ((ex, src), snd x)
738
+ only_max (src, [x]) = Nothing
739
+ -- TODO: What does it mean in HPC if there are multiple labels here?
740
+ only_max (src, xs)
741
+ | any isOkBox xs =
742
+ Just ((ex, src), maximum $ map snd xs)
743
+ only_max (src, xs) = trace (show xs) Nothing
771
744
772
745
-- Run HPC to get the trace information.
773
746
traceTargets ::
@@ -779,19 +752,13 @@ traceTargets ::
779
752
traceTargets _ _ _ [] = return []
780
753
-- Note: we call runGhc' here directly, since we want every trace to be a
781
754
-- new ghc thread (since we set the dynflags per module)
782
- traceTargets cc@ CompConf {.. } tp@ EProb {.. } exprs' ps_w_ce =
755
+ traceTargets cc@ CompConf {.. } tp@ EProb {.. } exprs ps_w_ce =
783
756
runGhc' cc $ do
784
757
seed <- liftIO newSeed
785
- let traceHash = flip showHex " " $ abs $ hashString $ showSDocUnsafe $ ppr (exprs' , ps_w_ce, seed)
758
+ let traceHash = flip showHex " " $ abs $ hashString $ showSDocUnsafe $ ppr (exprs, ps_w_ce, seed)
786
759
tempDir = tempDirBase </> " trace" </> traceHash
787
760
the_f = tempDir </> (" FakeTraceTarget" ++ traceHash) <.> " hs"
788
761
liftIO $ createDirectoryIfMissing True tempDir
789
- (exprs, realSpan) <- case exprs' of
790
- ((L (RealSrcSpan realSpan) _) : _) -> return (exprs', realSpan)
791
- _ -> do
792
- ~ tl@ (RealSrcSpan rsp) <- fakeBaseLoc cc tp exprs'
793
- let exprs = map (L tl . unLoc) exprs'
794
- return (exprs, rsp)
795
762
let correl =
796
763
zipWith
797
764
( \ (nm, _, _) e ->
@@ -801,33 +768,11 @@ traceTargets cc@CompConf {..} tp@EProb {..} exprs' ps_w_ce =
801
768
e_prog
802
769
exprs
803
770
fake_target_names = Set. fromList $ map (\ (n, _, _) -> n) correl
804
- toDom :: (TixModule , Mix ) -> [MixEntryDom [(BoxLabel , Integer )]]
805
- toDom (TixModule _ _ _ ts, Mix _ _ _ _ es) =
806
- createMixEntryDom $ zipWith (\ t (pos, bl) -> (pos, (bl, t))) ts es
807
- isTarget Node {rootLabel = (_, [(TopLevelBox [ftn], _)])} =
808
- ftn `Set.member` fake_target_names
809
- isTarget _ = False
810
- -- We convert the HpcPos to the equivalent span we would get if we'd
811
- -- parsed and compiled the expression directly.
812
- toFakeSpan :: FilePath -> HpcPos -> HpcPos -> SrcSpan
813
- toFakeSpan the_f root sp = mkSrcSpan start end
814
- where
815
- fname = fsLit $ takeFileName the_f
816
- (_, _, rel, rec ) = fromHpcPos root
817
- eloff = rel - srcSpanEndLine realSpan
818
- ecoff = rec - srcSpanEndCol realSpan
819
- (sl, sc, el, ec) = fromHpcPos sp
820
- -- We add two spaces before every line in the source.
821
- start = mkSrcLoc fname (sl - eloff) (sc - ecoff - 1 )
822
- -- GHC Srcs end one after the end
823
- end = mkSrcLoc fname (el - eloff) (ec - ecoff)
824
771
mname = filter isAlphaNum $ dropExtension $ takeFileName the_f
825
772
modTxt = exprToTraceModule cc tp seed mname correl ps_w_ce
826
773
exeName = dropExtension the_f
827
774
mixFilePath = tempDir
828
- timeoutVal = fromIntegral timeout
829
775
830
- liftIO $ logStr DEBUG modTxt
831
776
liftIO $ writeFile the_f modTxt
832
777
_ <- liftIO $ mapM (logStr DEBUG ) $ lines modTxt
833
778
-- We set the module as the main module, which makes GHC generate
@@ -858,6 +803,18 @@ traceTargets cc@CompConf {..} tp@EProb {..} exprs' ps_w_ce =
858
803
859
804
_ <- load (LoadUpTo target_name)
860
805
806
+ modul@ ParsedModule {pm_parsed_source = (L _ HsModule {.. })} <-
807
+ getModSummary target_name >>= parseModule
808
+ -- Retrieves the Values declared in the given Haskell-Module
809
+ let our_targets :: Map String (LHsExpr GhcPs )
810
+ our_targets = Map. fromList $ mapMaybe fromValD hsmodDecls
811
+ where
812
+ fromValD (L l (ValD _ b@ FunBind {.. }))
813
+ | rdrNameToStr (unLoc fun_id) `elem` fake_target_names,
814
+ Just ex <- unFun b =
815
+ Just (rdrNameToStr $ unLoc fun_id, ex)
816
+ fromValD _ = Nothing
817
+
861
818
-- We should for here in case it doesn't terminate, and modify
862
819
-- the run function so that it use the trace reflect functionality
863
820
-- to timeout and dump the tix file if possible.
@@ -908,21 +865,40 @@ traceTargets cc@CompConf {..} tp@EProb {..} exprs' ps_w_ce =
908
865
-- TODO: When run in parallel, this can fail
909
866
let rm m = (m,) <$> readMix [mixFilePath] (Right m)
910
867
isTargetMod = (mname == ) . tixModuleName
868
+ toDom :: (TixModule , Mix ) -> [MixEntryDom [(BoxLabel , Integer )]]
869
+ toDom (TixModule _ _ _ ts, Mix _ _ _ _ es) =
870
+ createMixEntryDom $ zipWith (\ t (pos, bl) -> (pos, (bl, t))) ts es
871
+
872
+ nd n@ Node {rootLabel = (root, _)} =
873
+ fmap (Data.Bifunctor. first (toSpan the_f)) n
874
+ wTarget n@ Node {rootLabel = (_, [(TopLevelBox [ftn], _)])} =
875
+ (,nd n) <$> our_targets Map. !? ftn
876
+ wTarget _ = Nothing
877
+ -- We convert the HpcPos to the equivalent span we would get if we'd
878
+ -- parsed and compiled the expression directly.
879
+ toSpan :: FilePath -> HpcPos -> SrcSpan
880
+ toSpan the_f sp = mkSrcSpan start end
881
+ where
882
+ fname = fsLit the_f
883
+ (sl, sc, el, ec) = fromHpcPos sp
884
+ start = mkSrcLoc fname sl sc
885
+ -- HPC and GHC have different philosophies
886
+ end = mkSrcLoc fname el (ec + 1 )
911
887
case tix of
912
888
Just (Tix mods) -> do
913
889
-- We throw away any extra functions in the file, such as
914
890
-- the properties and the main function, and only look at
915
891
-- the ticks for our expression
916
892
let fake_only = filter isTargetMod mods
917
- nd n@ Node {rootLabel = (root, _)} =
918
- fmap (Data.Bifunctor. first (toFakeSpan the_f root)) n
919
- res <- map nd . filter isTarget . concatMap toDom <$> mapM rm fake_only
893
+ res <- mapMaybe wTarget . concatMap toDom <$> mapM rm fake_only
920
894
return $ Just res
921
895
_ -> return Nothing
922
896
923
897
res <- liftIO $ mapM (runTrace . fst ) $ zip [0 .. ] ps_w_ce
924
898
cleanupAfterLoads tempDir mname dynFlags
925
899
return res
900
+ where
901
+ timeoutVal = fromIntegral timeout
926
902
traceTargets _ _ [] _ = error " No fix!"
927
903
traceTargets _ ExProb {} _ _ = error " Exprobs not supported!"
928
904
0 commit comments