@@ -1,211 +1,81 @@
1−{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
4module StackTrace.Plugin (plugin) where
2module StackTrace.Plugin (plugin) where
6−import Control.Arrow (first)
7−import Data.Monoid (Any(Any, getAny))
8−import GHC.Types.SrcLoc
9−#if __GLASGOW_HASKELL__ >= 900
13import GhcPlugins
4import GhcPlugins
14−#endif
5+import TcRnTypes (IfM, TcM, TcGblEnv, tcg_binds, tcg_rn_decls)
15−#if __GLASGOW_HASKELL__ >= 810
6+import HsExtension (GhcTc, GhcRn)
16−import GHC.Hs
7+import HsDecls (HsGroup)
17−#endif
8+import HsExpr (LHsExpr)
18−#if __GLASGOW_HASKELL__ < 810
19import HsSyn
9import HsSyn
22−type Traversal s t a b
11+import Data.Maybe
23− = forall f. Applicative f =>
24− (a -> f b) -> s -> f t
26−type Traversal' s a = Traversal s s a a
28plugin :: Plugin
13plugin :: Plugin
14+plugin = defaultPlugin
29−plugin = defaultPlugin {parsedResultAction = parsedPlugin, pluginRecompile = purePlugin}
15+ { parsedResultAction = parsedPlugin
32− [CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule
18+parsedPlugin :: [CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule
33parsedPlugin _ _ pm = do
19parsedPlugin _ _ pm = do
20+ dflags <- getDynFlags
22+ let extract = hsmodImports . unLoc
23+ addGHCStackMod = noLoc $ simpleImportDecl $ mkModuleName "GHC.Stack"
34− let m = updateHsModule <$> hpm_module pm
25+ m = updateHsModule addGHCStackMod updateHsmodDecl <$> hpm_module pm
35− pm' = pm {hpm_module = m}
26+ pm' = pm { hpm_module = m }
36 return pm'
28 return pm'
38−-- Use qualified import for GHC.Stack as "AutoImported.GHC.Stack"
30+updateHsModule :: LImportDecl GhcPs -> (LHsDecl GhcPs -> LHsDecl GhcPs) -> HsModule GhcPs -> HsModule GhcPs
39−-- ...this should not interfere with other imports...
31+updateHsModule importDecl update hsm = hsm
40−ghcStackModuleName :: ModuleName
32+ { hsmodImports = importDecl:decls
41−ghcStackModuleName = mkModuleName "AutoImported.GHC.Stack"
33+ , hsmodDecls = map update lhss
43−#if __GLASGOW_HASKELL__ < 810
44−importDeclQualified :: Bool
45−importDeclQualified = True
47−importDeclQualified :: ImportDeclQualifiedStyle
48−importDeclQualified = QualifiedPre
51−ghcStackImport :: Located (ImportDecl (GhcPass p))
54− (simpleImportDecl $ mkModuleName "GHC.Stack")
55− { ideclQualified = importDeclQualified, ideclAs = Just $ noLoc ghcStackModuleName }
57− -- This is for GHC-9 related problems. @noLoc@ causes GHC to throw warnings
36+ decls = hsmodImports hsm
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
65−updateHsModule :: HsModule GhcPs -> HsModule GhcPs
68− hsm {hsmodImports = hsmodImports', hsmodDecls = hsmodDecls'}
70− -- Traverse the haskell AST; if we have to add some HasStack
71− -- constraint we set a flag in a (Any,) functor.
72− -- ...it'd be simpler to check if before == after, but Haskell AST
73− -- doesn't have Eq instances.
74− (updatedP, hsmodDecls') =
76− (traverse . astTraversal) updateHsType (hsmodDecls hsm)
37+ lhss = hsmodDecls hsm
78− -- Only import GHC.Stack if needed for a constraint we introduced
81− then [ghcStackImport]
85− astTraversal :: Traversal' (LHsDecl GhcPs) (HsType GhcPs)
86− astTraversal = updateHsmodDecl
92--------------
39--------------
93−updateHsmodDecl :: Traversal' (LHsDecl GhcPs) (HsDecl GhcPs)
40+
94−updateHsmodDecl = traverse
41+updateHsmodDecl :: LHsDecl GhcPs -> LHsDecl GhcPs
95−
42+updateHsmodDecl = fmap updateHsDecl
96−updateHsDecl :: Traversal' (HsDecl GhcPs) (LHsSigWcType GhcPs)
43+
97−updateHsDecl f (SigD xSig s) = SigD xSig <$> updateSig f s
44+updateHsDecl :: HsDecl GhcPs -> HsDecl GhcPs
98−updateHsDecl f (ValD xVal hsBind) = ValD xVal <$> updateHsBind f hsBind
45+updateHsDecl (SigD xSig s) = SigD xSig (updateSig s)
99−updateHsDecl _ sig = pure sig
46+updateHsDecl decl = decl
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)
146−updateSig :: Traversal' (Sig GhcPs) (LHsSigWcType GhcPs)
48+updateSig :: Sig GhcPs -> Sig GhcPs
147−updateSig f (TypeSig xSig ls t) = TypeSig xSig ls <$> f t
49+updateSig (TypeSig xSig ls t) = TypeSig xSig ls (updateLHsSigWcType t)
148−updateSig _ sig = pure sig
50+updateSig sig = sig
150−updateLHsSigWsType :: Traversal' (LHsSigWcType GhcPs) (LHsSigType GhcPs)
52+updateLHsSigWcType :: LHsSigWcType GhcPs -> LHsSigWcType GhcPs
151−updateLHsSigWsType f lhs@HsWC {} =
152− (\x -> lhs {hswc_body = x}) <$> f (hswc_body lhs)
53+updateLHsSigWcType lhs@HsWC{} = lhs { hswc_body = updateLHsSigType (hswc_body lhs) }
153−#if __GLASGOW_HASKELL__ < 900
54+updateLHsSigWcType lhs@XHsWildCardBndrs{} = lhs
154−updateLHsSigWsType _ lhs = pure lhs
55+
157−updateLHsSigType :: Traversal' (LHsSigType GhcPs) (LHsType GhcPs)
56+updateLHsSigType :: LHsSigType GhcPs -> LHsSigType GhcPs
158−updateLHsSigType f lhs@HsIB {} =
159− (\x -> lhs {hsib_body = x}) <$> f (hsib_body lhs)
57+updateLHsSigType lhs@HsIB{} = lhs { hsib_body = updateLHsType (hsib_body lhs )}
160−#if __GLASGOW_HASKELL__ < 900
161−updateLHsSigType _ lhs = pure lhs
58+updateLHsSigType lhs@XHsImplicitBndrs{} = lhs
164−updateLHsType :: Traversal' (LHsType GhcPs) (HsType GhcPs)
60+updateLHsType :: LHsType GhcPs -> LHsType GhcPs
165−updateLHsType = traverse
61+updateLHsType = fmap updateHsType
167-- Main process
63-- Main process
168−updateHsType :: HsType GhcPs -> (Any, HsType GhcPs)
64+updateHsType :: HsType GhcPs -> HsType GhcPs
169−updateHsType ty@(HsQualTy xty ctxt body) =
65+updateHsType ty@(HsQualTy xty ctxt body) = HsQualTy xty (fmap appendHSC ctxt) body
170− if hasHasCallStack (unLoc ctxt)
172− else flagASTModified $ HsQualTy xty (fmap appendHSC ctxt) body
173−updateHsType ty@HsTyVar {} =
66+updateHsType ty@HsTyVar{} = HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
174− flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
175−updateHsType ty@HsAppTy {} =
67+updateHsType ty@HsAppTy{} = HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
176− flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
177−updateHsType ty@HsFunTy {} =
68+updateHsType ty@HsFunTy{} = HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
178− flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
179−updateHsType ty@HsListTy {} =
69+updateHsType ty@HsListTy{} = HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
180− flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
181−updateHsType ty@HsTupleTy {} =
70+updateHsType ty@HsTupleTy{} = HsQualTy noExt (noLoc $ appendHSC []) (noLoc ty)
182− flagASTModified $ HsQualTy xQualTy (noLoc $ appendHSC []) (noLoc ty)
183−updateHsType ty = pure ty
71+updateHsType ty = ty
185−#if __GLASGOW_HASKELL__ < 810
189−xQualTy :: NoExtField
193−flagASTModified :: a -> (Any, a)
194−flagASTModified a = (Any True, a)
196appendHSC :: HsContext GhcPs -> HsContext GhcPs
73appendHSC :: HsContext GhcPs -> HsContext GhcPs
197appendHSC cs = mkHSC : cs
74appendHSC 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
206-- make HasCallStack => constraint
76-- make HasCallStack => constraint
207mkHSC :: LHsType GhcPs
77mkHSC :: LHsType GhcPs
208−mkHSC = noLoc $ HsTyVar xQualTy NotPromoted lId
78+mkHSC = noLoc $ HsTyVar noExt NotPromoted lId
210lId :: Located (IdP GhcPs)
80lId :: Located (IdP GhcPs)
211−lId = noLoc $ mkRdrQual ghcStackModuleName $ mkClsOcc "HasCallStack"
81+lId = noLoc $ mkRdrUnqual $ mkClsOcc "HasCallStack"