@@ -5,6 +5,7 @@ module StackTrace.Plugin (plugin) where
55
66import Control.Arrow (first)
77import Data.Monoid (Any(Any, getAny))
8+import GHC.Types.SrcLoc
89#if __GLASGOW_HASKELL__ >= 900
910import GHC.Plugins
1011#else
@@ -49,9 +50,14 @@ importDeclQualified = QualifiedPre
4950
5051ghcStackImport :: Located (ImportDecl (GhcPass p))
5152ghcStackImport =
52− noLoc $
53+ L srcSpan $
5354 (simpleImportDecl $ mkModuleName "GHC.Stack")
54− {ideclQualified = importDeclQualified, ideclAs = Just $ noLoc ghcStackModuleName}
55+ { ideclQualified = importDeclQualified, ideclAs = Just $ noLoc ghcStackModuleName }
56+ where
57+ -- This is for GHC-9 related problems. @noLoc@ causes GHC to throw warnings
58+ -- about unused imports. Even if the import is used
59+ -- See: https://github.com/waddlaw/haskell-stack-trace-plugin/issues/16
60+ srcSpan = RealSrcSpan (realSrcLocSpan $ mkRealSrcLoc "haskell-stack-trace-plugin:very-unique-file-name-to-avoid-collision" 1 1) Nothing
5561
5662#if __GLASGOW_HASKELL__ >= 900
5763updateHsModule :: HsModule -> HsModule
@@ -79,7 +85,6 @@ updateHsModule hsm =
7985 astTraversal :: Traversal' (LHsDecl GhcPs) (HsType GhcPs)
8086 astTraversal = updateHsmodDecl
8187 . updateHsDecl
82− . updateSig
8388 . updateLHsSigWsType
8489 . updateLHsSigType
8590 . updateLHsType
@@ -88,10 +93,56 @@ updateHsModule hsm =
8893updateHsmodDecl :: Traversal' (LHsDecl GhcPs) (HsDecl GhcPs)
8994updateHsmodDecl = traverse
9095
91−updateHsDecl :: Traversal' (HsDecl GhcPs) (Sig GhcPs)
92−updateHsDecl f (SigD xSig s) = SigD xSig <$> f s
96+updateHsDecl :: Traversal' (HsDecl GhcPs) (LHsSigWcType GhcPs)
97+updateHsDecl f (SigD xSig s) = SigD xSig <$> updateSig f s
98+updateHsDecl f (ValD xVal hsBind) = ValD xVal <$> updateHsBind f hsBind
9399updateHsDecl _ sig = pure sig
94100
101+updateHsBind :: Traversal' (HsBind GhcPs) (LHsSigWcType GhcPs)
102+updateHsBind f bind@FunBind {} = (\x -> bind {fun_matches = x}) <$> updateMatchGroup f (fun_matches bind)
103+updateHsBind _ bind = pure bind
104+
105+updateMatchGroup :: Traversal' (MatchGroup GhcPs (LHsExpr GhcPs)) (LHsSigWcType GhcPs)
106+updateMatchGroup f mg@MG {} = (\x -> mg {mg_alts = x}) <$> updateLLMatch f (mg_alts mg)
107+#if __GLASGOW_HASKELL__ < 900
108+updateMatchGroup _ mg = pure mg
109+#endif
110+
111+updateLocated :: Functor f => (a -> b -> f c) -> a -> Located b -> f (Located c)
112+updateLocated f g (L l e) = L l <$> f g e
113+
114+updateLLMatch :: Traversal' (Located [LMatch GhcPs (LHsExpr GhcPs)]) (LHsSigWcType GhcPs)
115+updateLLMatch = updateLocated updateLMatches
116+
117+updateLMatches :: Traversal' [LMatch GhcPs (LHsExpr GhcPs)] (LHsSigWcType GhcPs)
118+updateLMatches f = traverse (updateLocated updateMatch f)
119+
120+updateMatch :: Traversal' (Match GhcPs (LHsExpr GhcPs)) (LHsSigWcType GhcPs)
121+updateMatch f m@Match {} = (\x -> m {m_grhss = x}) <$> updateGrhss f (m_grhss m)
122+#if __GLASGOW_HASKELL__ < 900
123+updateMatch _ m = pure m
124+#endif
125+
126+updateGrhss :: Traversal' (GRHSs GhcPs (LHsExpr GhcPs)) (LHsSigWcType GhcPs)
127+updateGrhss f grhss@GRHSs {} = (\x -> grhss {grhssLocalBinds = x}) <$> updateLHsLocalBinds f (grhssLocalBinds grhss)
128+#if __GLASGOW_HASKELL__ < 900
129+updateGrhss _ grhss = pure grhss
130+#endif
131+
132+updateLHsLocalBinds :: Traversal' (LHsLocalBinds GhcPs) (LHsSigWcType GhcPs)
133+updateLHsLocalBinds = updateLocated updateLocalBinds
134+
135+updateLocalBinds :: Traversal' (HsLocalBinds GhcPs) (LHsSigWcType GhcPs)
136+updateLocalBinds f (HsValBinds xHsValBinds hsValBindsLR) = HsValBinds xHsValBinds <$> updateHsValBindsLR f hsValBindsLR
137+updateLocalBinds _ hsValBinds = pure hsValBinds
138+
139+updateHsValBindsLR :: Traversal' (HsValBindsLR GhcPs GhcPs) (LHsSigWcType GhcPs)
140+updateHsValBindsLR f (ValBinds xValBinds lHsBindsLR lSigs) = ValBinds xValBinds lHsBindsLR <$> updateLSigs f lSigs
141+updateHsValBindsLR _ valBinds = pure valBinds
142+
143+updateLSigs :: Traversal' [LSig GhcPs] (LHsSigWcType GhcPs)
144+updateLSigs f = traverse (updateLocated updateSig f)
145+
95146updateSig :: Traversal' (Sig GhcPs) (LHsSigWcType GhcPs)
96147updateSig f (TypeSig xSig ls t) = TypeSig xSig ls <$> f t
97148updateSig _ sig = pure sig
@@ -115,8 +166,10 @@ updateLHsType = traverse
115166
116167-- Main process
117168updateHsType :: HsType GhcPs -> (Any, HsType GhcPs)
118−updateHsType (HsQualTy xty ctxt body) =
119− flagASTModified $ HsQualTy xty (fmap appendHSC ctxt) body
169+updateHsType ty@(HsQualTy xty ctxt body) =
170+ if hasHasCallStack (unLoc ctxt)
171+ then pure ty
172+ else flagASTModified $ HsQualTy xty (fmap appendHSC ctxt) body
120173updateHsType ty@HsTyVar {} =
121174 flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
122175updateHsType ty@HsAppTy {} =
@@ -143,6 +196,13 @@ flagASTModified a = (Any True, a)
143196appendHSC :: HsContext GhcPs -> HsContext GhcPs
144197appendHSC cs = mkHSC : cs
145198
199+hasHasCallStack :: HsContext GhcPs -> Bool
200+hasHasCallStack = any (checkHsType . unLoc)
201+ where
202+ checkHsType :: HsType GhcPs -> Bool
203+ checkHsType (HsTyVar _ _ lid) = unLoc lid == (mkRdrUnqual $ mkClsOcc "HasCallStack")
204+ checkHsType _ = False
205+
146206-- make HasCallStack => constraint
147207mkHSC :: LHsType GhcPs
148208mkHSC = noLoc $ HsTyVar xQualTy NotPromoted lId