@@ -1,11 +1,23 @@
1{-# LANGUAGE RankNTypes #-}
1{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module StackTrace.Plugin (plugin) where
4module StackTrace.Plugin (plugin) where
5import Control.Arrow (first)
6import Control.Arrow (first)
6import Data.Monoid (Any(Any, getAny))
7import Data.Monoid (Any(Any, getAny))
8+import GHC.Types.SrcLoc
9+#if __GLASGOW_HASKELL__ >= 900
7import GhcPlugins
13import GhcPlugins
15+#if __GLASGOW_HASKELL__ >= 810
18+#if __GLASGOW_HASKELL__ < 810
8import HsSyn
19import HsSyn
10type Traversal s t a b
22type Traversal s t a b
11 = forall f. Applicative f =>
23 = forall f. Applicative f =>
@@ -28,13 +40,30 @@ parsedPlugin _ _ pm = do
28ghcStackModuleName :: ModuleName
40ghcStackModuleName :: ModuleName
29ghcStackModuleName = mkModuleName "AutoImported.GHC.Stack"
41ghcStackModuleName = mkModuleName "AutoImported.GHC.Stack"
43+#if __GLASGOW_HASKELL__ < 810
44+importDeclQualified :: Bool
45+importDeclQualified = True
47+importDeclQualified :: ImportDeclQualifiedStyle
48+importDeclQualified = QualifiedPre
31ghcStackImport :: Located (ImportDecl (GhcPass p))
51ghcStackImport :: Located (ImportDecl (GhcPass p))
32ghcStackImport =
52ghcStackImport =
33− noLoc $
53+ L srcSpan $
34 (simpleImportDecl $ mkModuleName "GHC.Stack")
54 (simpleImportDecl $ mkModuleName "GHC.Stack")
35− {ideclQualified = True, ideclAs = Just $ noLoc ghcStackModuleName}
55+ { ideclQualified = importDeclQualified, ideclAs = Just $ noLoc ghcStackModuleName }
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
62+#if __GLASGOW_HASKELL__ >= 900
63+updateHsModule :: HsModule -> HsModule
37updateHsModule :: HsModule GhcPs -> HsModule GhcPs
65updateHsModule :: HsModule GhcPs -> HsModule GhcPs
38updateHsModule hsm =
67updateHsModule hsm =
39 hsm {hsmodImports = hsmodImports', hsmodDecls = hsmodDecls'}
68 hsm {hsmodImports = hsmodImports', hsmodDecls = hsmodDecls'}
@@ -56,7 +85,6 @@ updateHsModule hsm =
56 astTraversal :: Traversal' (LHsDecl GhcPs) (HsType GhcPs)
85 astTraversal :: Traversal' (LHsDecl GhcPs) (HsType GhcPs)
57 astTraversal = updateHsmodDecl
86 astTraversal = updateHsmodDecl
58 . updateHsDecl
87 . updateHsDecl
60 . updateLHsSigWsType
88 . updateLHsSigWsType
61 . updateLHsSigType
89 . updateLHsSigType
62 . updateLHsType
90 . updateLHsType
@@ -65,10 +93,56 @@ updateHsModule hsm =
65updateHsmodDecl :: Traversal' (LHsDecl GhcPs) (HsDecl GhcPs)
93updateHsmodDecl :: Traversal' (LHsDecl GhcPs) (HsDecl GhcPs)
66updateHsmodDecl = traverse
94updateHsmodDecl = traverse
68−updateHsDecl :: Traversal' (HsDecl GhcPs) (Sig GhcPs)
96+updateHsDecl :: Traversal' (HsDecl GhcPs) (LHsSigWcType GhcPs)
69−updateHsDecl f (SigD xSig s) = SigD xSig <$> f s
97+updateHsDecl f (SigD xSig s) = SigD xSig <$> updateSig f s
98+updateHsDecl f (ValD xVal hsBind) = ValD xVal <$> updateHsBind f hsBind
70updateHsDecl _ sig = pure sig
99updateHsDecl _ sig = pure sig
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
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
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
114+updateLLMatch :: Traversal' (Located [LMatch GhcPs (LHsExpr GhcPs)]) (LHsSigWcType GhcPs)
115+updateLLMatch = updateLocated updateLMatches
117+updateLMatches :: Traversal' [LMatch GhcPs (LHsExpr GhcPs)] (LHsSigWcType GhcPs)
118+updateLMatches f = traverse (updateLocated updateMatch f)
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
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
132+updateLHsLocalBinds :: Traversal' (LHsLocalBinds GhcPs) (LHsSigWcType GhcPs)
133+updateLHsLocalBinds = updateLocated updateLocalBinds
135+updateLocalBinds :: Traversal' (HsLocalBinds GhcPs) (LHsSigWcType GhcPs)
136+updateLocalBinds f (HsValBinds xHsValBinds hsValBindsLR) = HsValBinds xHsValBinds <$> updateHsValBindsLR f hsValBindsLR
137+updateLocalBinds _ hsValBinds = pure hsValBinds
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
143+updateLSigs :: Traversal' [LSig GhcPs] (LHsSigWcType GhcPs)
144+updateLSigs f = traverse (updateLocated updateSig f)
72updateSig :: Traversal' (Sig GhcPs) (LHsSigWcType GhcPs)
146updateSig :: Traversal' (Sig GhcPs) (LHsSigWcType GhcPs)
73updateSig f (TypeSig xSig ls t) = TypeSig xSig ls <$> f t
147updateSig f (TypeSig xSig ls t) = TypeSig xSig ls <$> f t
74updateSig _ sig = pure sig
148updateSig _ sig = pure sig
@@ -76,41 +150,62 @@ updateSig _ sig = pure sig
76updateLHsSigWsType :: Traversal' (LHsSigWcType GhcPs) (LHsSigType GhcPs)
150updateLHsSigWsType :: Traversal' (LHsSigWcType GhcPs) (LHsSigType GhcPs)
77updateLHsSigWsType f lhs@HsWC {} =
151updateLHsSigWsType f lhs@HsWC {} =
78 (\x -> lhs {hswc_body = x}) <$> f (hswc_body lhs)
152 (\x -> lhs {hswc_body = x}) <$> f (hswc_body lhs)
153+#if __GLASGOW_HASKELL__ < 900
79updateLHsSigWsType _ lhs = pure lhs
154updateLHsSigWsType _ lhs = pure lhs
81updateLHsSigType :: Traversal' (LHsSigType GhcPs) (LHsType GhcPs)
157updateLHsSigType :: Traversal' (LHsSigType GhcPs) (LHsType GhcPs)
82updateLHsSigType f lhs@HsIB {} =
158updateLHsSigType f lhs@HsIB {} =
83 (\x -> lhs {hsib_body = x}) <$> f (hsib_body lhs)
159 (\x -> lhs {hsib_body = x}) <$> f (hsib_body lhs)
160+#if __GLASGOW_HASKELL__ < 900
84updateLHsSigType _ lhs = pure lhs
161updateLHsSigType _ lhs = pure lhs
86updateLHsType :: Traversal' (LHsType GhcPs) (HsType GhcPs)
164updateLHsType :: Traversal' (LHsType GhcPs) (HsType GhcPs)
87updateLHsType = traverse
165updateLHsType = traverse
89-- Main process
167-- Main process
90updateHsType :: HsType GhcPs -> (Any, HsType GhcPs)
168updateHsType :: HsType GhcPs -> (Any, HsType GhcPs)
91−updateHsType (HsQualTy xty ctxt body) =
169+updateHsType ty@(HsQualTy xty ctxt body) =
170+ if hasHasCallStack (unLoc ctxt)
92− flagASTModified $ HsQualTy xty (fmap appendHSC ctxt) body
172+ else flagASTModified $ HsQualTy xty (fmap appendHSC ctxt) body
93updateHsType ty@HsTyVar {} =
173updateHsType ty@HsTyVar {} =
94− flagASTModified $ HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
174+ flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
95updateHsType ty@HsAppTy {} =
175updateHsType ty@HsAppTy {} =
96− flagASTModified $ HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
176+ flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
97updateHsType ty@HsFunTy {} =
177updateHsType ty@HsFunTy {} =
98− flagASTModified $ HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
178+ flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
99updateHsType ty@HsListTy {} =
179updateHsType ty@HsListTy {} =
100− flagASTModified $ HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
180+ flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
101updateHsType ty@HsTupleTy {} =
181updateHsType ty@HsTupleTy {} =
102− flagASTModified $ HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
182+ flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
103updateHsType ty = pure ty
183updateHsType ty = pure ty
185+#if __GLASGOW_HASKELL__ < 810
189+xQualTy :: NoExtField
105flagASTModified :: a -> (Any, a)
193flagASTModified :: a -> (Any, a)
106flagASTModified a = (Any True, a)
194flagASTModified a = (Any True, a)
108appendHSC :: HsContext GhcPs -> HsContext GhcPs
196appendHSC :: HsContext GhcPs -> HsContext GhcPs
109appendHSC cs = mkHSC : cs
197appendHSC cs = mkHSC : cs
199+hasHasCallStack :: HsContext GhcPs -> Bool
200+hasHasCallStack = any (checkHsType . unLoc)
202+ checkHsType :: HsType GhcPs -> Bool
203+ checkHsType (HsTyVar _ _ lid) = unLoc lid == (mkRdrUnqual $ mkClsOcc "HasCallStack")
204+ checkHsType _ = False
111-- make HasCallStack => constraint
206-- make HasCallStack => constraint
112mkHSC :: LHsType GhcPs
207mkHSC :: LHsType GhcPs
113−mkHSC = noLoc $ HsTyVar noExt NotPromoted lId
208+mkHSC = noLoc $ HsTyVar xQualTy NotPromoted lId
115lId :: Located (IdP GhcPs)
210lId :: Located (IdP GhcPs)
116lId = noLoc $ mkRdrQual ghcStackModuleName $ mkClsOcc "HasCallStack"
211lId = noLoc $ mkRdrQual ghcStackModuleName $ mkClsOcc "HasCallStack"