@@ -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 )
@@ -55,7 +56,7 @@ import DynFlags
55
56
import Endemic.Check
56
57
import Endemic.Configuration
57
58
import Endemic.Plugin
58
- import Endemic.Traversals (flattenExpr )
59
+ import Endemic.Traversals (flattenExpr , sanctifyExpr )
59
60
import Endemic.Types
60
61
import Endemic.Util
61
62
import ErrUtils (ErrMsg (errMsgSeverity ), errMsgSpan , pprErrMsgBagWithLoc )
@@ -67,6 +68,7 @@ import GHC.Prim (unsafeCoerce#)
67
68
import GhcPlugins hiding (exprType )
68
69
import Numeric (showHex )
69
70
import PrelNames (toDynName )
71
+ import qualified Pretty as Pretty
70
72
import RnExpr (rnLExpr )
71
73
import StringBuffer (stringToStringBuffer )
72
74
import System.Directory (createDirectoryIfMissing , doesDirectoryExist , doesFileExist , makeAbsolute , removeDirectory , removeDirectoryRecursive , removeFile )
@@ -649,44 +651,6 @@ moduleToProb baseCC@CompConf {tempDirBase = baseTempDir, ..} mod_path mb_target
649
651
-- _ -> int_prob
650
652
return (cc', tc_modul, int_prob)
651
653
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
654
-- | Runs a GHC action and cleans up any hpc-directories that might have been
691
655
-- created as a side-effect.
692
656
-- TODO: Does this slow things down massively? We lose out on the pre-generated
@@ -762,12 +726,22 @@ traceTarget ::
762
726
EProp ->
763
727
[RExpr ] ->
764
728
IO (Maybe TraceRes )
765
- traceTarget cc tp e fp ce = head <$> ( traceTargets cc tp e [(fp, ce)])
729
+ traceTarget cc tp e fp ce = head <$> traceTargets cc tp e [(fp, ce)]
766
730
767
- toInvokes :: Trace -> Map. Map SrcSpan Integer
768
- toInvokes res = Map. fromList $ map only_max $ flatten res
731
+ toInvokes :: Trace -> Map. Map ( EExpr , SrcSpan ) Integer
732
+ toInvokes (ex, res) = Map. fromList $ mapMaybe only_max $ flatten res
769
733
where
770
- only_max (src, r) = (mkInteractive src, maximum $ map snd r)
734
+ only_max :: (SrcSpan , [(BoxLabel , Integer )]) -> Maybe ((EExpr , SrcSpan ), Integer )
735
+ -- TODO: What does it mean if there are multiple labels here?
736
+ only_max (src, xs)
737
+ | xboxes <- filter isXBox xs,
738
+ not (null xboxes),
739
+ s <- maximum (map snd xboxes) =
740
+ Just ((ex, src), s)
741
+ where
742
+ isXBox (ExpBox _, _) = True
743
+ isXBox _ = False
744
+ only_max _ = Nothing
771
745
772
746
-- Run HPC to get the trace information.
773
747
traceTargets ::
@@ -779,19 +753,13 @@ traceTargets ::
779
753
traceTargets _ _ _ [] = return []
780
754
-- Note: we call runGhc' here directly, since we want every trace to be a
781
755
-- new ghc thread (since we set the dynflags per module)
782
- traceTargets cc@ CompConf {.. } tp@ EProb {.. } exprs' ps_w_ce =
756
+ traceTargets cc@ CompConf {.. } tp@ EProb {.. } exprs ps_w_ce =
783
757
runGhc' cc $ do
784
758
seed <- liftIO newSeed
785
- let traceHash = flip showHex " " $ abs $ hashString $ showSDocUnsafe $ ppr (exprs' , ps_w_ce, seed)
759
+ let traceHash = flip showHex " " $ abs $ hashString $ showSDocUnsafe $ ppr (exprs, ps_w_ce, seed)
786
760
tempDir = tempDirBase </> " trace" </> traceHash
787
761
the_f = tempDir </> (" FakeTraceTarget" ++ traceHash) <.> " hs"
788
762
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
763
let correl =
796
764
zipWith
797
765
( \ (nm, _, _) e ->
@@ -801,33 +769,11 @@ traceTargets cc@CompConf {..} tp@EProb {..} exprs' ps_w_ce =
801
769
e_prog
802
770
exprs
803
771
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
772
mname = filter isAlphaNum $ dropExtension $ takeFileName the_f
825
773
modTxt = exprToTraceModule cc tp seed mname correl ps_w_ce
826
774
exeName = dropExtension the_f
827
775
mixFilePath = tempDir
828
- timeoutVal = fromIntegral timeout
829
776
830
- liftIO $ logStr DEBUG modTxt
831
777
liftIO $ writeFile the_f modTxt
832
778
_ <- liftIO $ mapM (logStr DEBUG ) $ lines modTxt
833
779
-- We set the module as the main module, which makes GHC generate
@@ -858,6 +804,18 @@ traceTargets cc@CompConf {..} tp@EProb {..} exprs' ps_w_ce =
858
804
859
805
_ <- load (LoadUpTo target_name)
860
806
807
+ modul@ ParsedModule {pm_parsed_source = (L _ HsModule {.. })} <-
808
+ getModSummary target_name >>= parseModule
809
+ -- Retrieves the Values declared in the given Haskell-Module
810
+ let our_targets :: Map String (LHsExpr GhcPs )
811
+ our_targets = Map. fromList $ mapMaybe fromValD hsmodDecls
812
+ where
813
+ fromValD (L l (ValD _ b@ FunBind {.. }))
814
+ | rdrNameToStr (unLoc fun_id) `elem` fake_target_names,
815
+ Just ex <- unFun b =
816
+ Just (rdrNameToStr $ unLoc fun_id, ex)
817
+ fromValD _ = Nothing
818
+
861
819
-- We should for here in case it doesn't terminate, and modify
862
820
-- the run function so that it use the trace reflect functionality
863
821
-- to timeout and dump the tix file if possible.
@@ -908,21 +866,40 @@ traceTargets cc@CompConf {..} tp@EProb {..} exprs' ps_w_ce =
908
866
-- TODO: When run in parallel, this can fail
909
867
let rm m = (m,) <$> readMix [mixFilePath] (Right m)
910
868
isTargetMod = (mname == ) . tixModuleName
869
+ toDom :: (TixModule , Mix ) -> [MixEntryDom [(BoxLabel , Integer )]]
870
+ toDom (TixModule _ _ _ ts, Mix _ _ _ _ es) =
871
+ createMixEntryDom $ zipWith (\ t (pos, bl) -> (pos, (bl, t))) ts es
872
+
873
+ nd n@ Node {rootLabel = (root, _)} =
874
+ fmap (Data.Bifunctor. first (toSpan the_f)) n
875
+ wTarget n@ Node {rootLabel = (_, [(TopLevelBox [ftn], _)])} =
876
+ (,nd n) <$> our_targets Map. !? ftn
877
+ wTarget _ = Nothing
878
+ -- We convert the HpcPos to the equivalent span we would get if we'd
879
+ -- parsed and compiled the expression directly.
880
+ toSpan :: FilePath -> HpcPos -> SrcSpan
881
+ toSpan the_f sp = mkSrcSpan start end
882
+ where
883
+ fname = fsLit the_f
884
+ (sl, sc, el, ec) = fromHpcPos sp
885
+ -- We add two spaces before every line in the source.
886
+ start = mkSrcLoc fname sl sc
887
+ end = mkSrcLoc fname el (ec + 1 )
911
888
case tix of
912
889
Just (Tix mods) -> do
913
890
-- We throw away any extra functions in the file, such as
914
891
-- the properties and the main function, and only look at
915
892
-- the ticks for our expression
916
893
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
894
+ res <- mapMaybe wTarget . concatMap toDom <$> mapM rm fake_only
920
895
return $ Just res
921
896
_ -> return Nothing
922
897
923
898
res <- liftIO $ mapM (runTrace . fst ) $ zip [0 .. ] ps_w_ce
924
899
cleanupAfterLoads tempDir mname dynFlags
925
900
return res
901
+ where
902
+ timeoutVal = fromIntegral timeout
926
903
traceTargets _ _ [] _ = error " No fix!"
927
904
traceTargets _ ExProb {} _ _ = error " Exprobs not supported!"
928
905
0 commit comments