root/compiler/ghci/Debugger.hs

Revision 222589a9f270d90f4ac21bf22b0a82e8ae126718, 9.1 KB (checked in by Simon Marlow <marlowsd@…>, 8 months ago)

fix bug in :show bindings when a variable is bound to an exception

  • Property mode set to 100644
Line 
1-----------------------------------------------------------------------------
2--
3-- GHCi Interactive debugging commands
4--
5-- Pepe Iborra (supported by Google SoC) 2006
6--
7-- ToDo: lots of violation of layering here.  This module should
8-- decide whether it is above the GHC API (import GHC and nothing
9-- else) or below it.
10--
11-----------------------------------------------------------------------------
12
13module Debugger (pprintClosureCommand, showTerm, pprTypeAndContents) where
14
15import Linker
16import RtClosureInspect
17
18import GhcMonad
19import HscTypes
20import Id
21import Name
22import Var hiding ( varName )
23import VarSet
24import UniqSupply
25import TcType
26import GHC
27import Outputable
28import PprTyThing
29import MonadUtils
30import Exception
31
32import Control.Monad
33import Data.List
34import Data.Maybe
35import Data.IORef
36
37import System.IO
38import GHC.Exts
39
40-------------------------------------
41-- | The :print & friends commands
42-------------------------------------
43pprintClosureCommand :: GhcMonad m => Bool -> Bool -> String -> m ()
44pprintClosureCommand bindThings force str = do
45  tythings <- (catMaybes . concat) `liftM`
46                 mapM (\w -> GHC.parseName w >>=
47                                mapM GHC.lookupName)
48                      (words str)
49  let ids = [id | AnId id <- tythings]
50
51  -- Obtain the terms and the recovered type information
52  (subst, terms) <- mapAccumLM go emptyTvSubst ids
53
54  -- Apply the substitutions obtained after recovering the types
55  modifySession $ \hsc_env ->
56    hsc_env{hsc_IC = substInteractiveContext (hsc_IC hsc_env) subst}
57
58  -- Finally, print the Terms
59  unqual  <- GHC.getPrintUnqual
60  docterms <- mapM showTerm terms
61  liftIO $ (printForUser stdout unqual . vcat)
62           (zipWith (\id docterm -> ppr id <+> char '=' <+> docterm)
63                    ids
64                    docterms)
65 where
66   -- Do the obtainTerm--bindSuspensions-computeSubstitution dance
67   go :: GhcMonad m => TvSubst -> Id -> m (TvSubst, Term)
68   go subst id = do
69       let id' = id `setIdType` substTy subst (idType id) 
70       term_    <- GHC.obtainTermFromId maxBound force id'
71       term     <- tidyTermTyVars term_
72       term'    <- if bindThings &&
73                      False == isUnliftedTypeKind (termType term)
74                     then bindSuspensions term
75                     else return term
76     -- Before leaving, we compare the type obtained to see if it's more specific
77     --  Then, we extract a substitution,
78     --  mapping the old tyvars to the reconstructed types.
79       let reconstructed_type = termType term
80       hsc_env <- getSession
81       case (improveRTTIType hsc_env (idType id) (reconstructed_type)) of
82         Nothing     -> return (subst, term')
83         Just subst' -> do { traceOptIf Opt_D_dump_rtti
84                               (fsep $ [text "RTTI Improvement for", ppr id,
85                                text "is the substitution:" , ppr subst'])
86                           ; return (subst `unionTvSubst` subst', term')}
87
88   tidyTermTyVars :: GhcMonad m => Term -> m Term
89   tidyTermTyVars t =
90     withSession $ \hsc_env -> do
91     let env_tvs      = tyThingsTyVars $ ic_tythings $ hsc_IC hsc_env
92         my_tvs       = termTyVars t
93         tvs          = env_tvs `minusVarSet` my_tvs
94         tyvarOccName = nameOccName . tyVarName
95         tidyEnv      = (initTidyOccEnv (map tyvarOccName (varSetElems tvs))
96                        , env_tvs `intersectVarSet` my_tvs)
97     return$ mapTermType (snd . tidyOpenType tidyEnv) t
98
99-- | Give names, and bind in the interactive environment, to all the suspensions
100--   included (inductively) in a term
101bindSuspensions :: GhcMonad m => Term -> m Term
102bindSuspensions t = do
103      hsc_env <- getSession
104      inScope <- GHC.getBindings
105      let ictxt        = hsc_IC hsc_env
106          prefix       = "_t"
107          alreadyUsedNames = map (occNameString . nameOccName . getName) inScope
108          availNames   = map ((prefix++) . show) [(1::Int)..] \\ alreadyUsedNames
109      availNames_var  <- liftIO $ newIORef availNames
110      (t', stuff)     <- liftIO $ foldTerm (nameSuspensionsAndGetInfos availNames_var) t
111      let (names, tys, hvals) = unzip3 stuff
112      let ids = [ mkVanillaGlobal name ty
113                | (name,ty) <- zip names tys]
114          new_ic = extendInteractiveContext ictxt (map AnId ids)
115      liftIO $ extendLinkEnv (zip names hvals)
116      modifySession $ \_ -> hsc_env {hsc_IC = new_ic }
117      return t'
118     where
119
120--    Processing suspensions. Give names and recopilate info
121        nameSuspensionsAndGetInfos :: IORef [String] ->
122                                       TermFold (IO (Term, [(Name,Type,HValue)]))
123        nameSuspensionsAndGetInfos freeNames = TermFold
124                      {
125                        fSuspension = doSuspension freeNames
126                      , fTerm = \ty dc v tt -> do
127                                    tt' <- sequence tt
128                                    let (terms,names) = unzip tt'
129                                    return (Term ty dc v terms, concat names)
130                      , fPrim    = \ty n ->return (Prim ty n,[])
131                      , fNewtypeWrap  = 
132                                \ty dc t -> do 
133                                    (term, names) <- t
134                                    return (NewtypeWrap ty dc term, names)
135                      , fRefWrap = \ty t -> do
136                                    (term, names) <- t
137                                    return (RefWrap ty term, names)
138                      }
139        doSuspension freeNames ct ty hval _name = do
140          name <- atomicModifyIORef freeNames (\x->(tail x, head x))
141          n <- newGrimName name
142          return (Suspension ct ty hval (Just n), [(n,ty,hval)])
143
144
145--  A custom Term printer to enable the use of Show instances
146showTerm :: GhcMonad m => Term -> m SDoc
147showTerm term = do
148    dflags       <- GHC.getSessionDynFlags
149    if dopt Opt_PrintEvldWithShow dflags
150       then cPprTerm (liftM2 (++) (\_y->[cPprShowable]) cPprTermBase) term
151       else cPprTerm cPprTermBase term
152 where
153  cPprShowable prec t@Term{ty=ty, val=val} =
154    if not (isFullyEvaluatedTerm t)
155     then return Nothing
156     else do
157        hsc_env <- getSession
158        dflags  <- GHC.getSessionDynFlags
159        do
160           (new_env, bname) <- bindToFreshName hsc_env ty "showme"
161           setSession new_env
162                      -- XXX: this tries to disable logging of errors
163                      -- does this still do what it is intended to do
164                      -- with the changed error handling and logging?
165           let noop_log _ _ _ _ = return ()
166               expr = "show " ++ showSDoc (ppr bname)
167           _ <- GHC.setSessionDynFlags dflags{log_action=noop_log}
168           txt_ <- withExtendedLinkEnv [(bname, val)]
169                                       (GHC.compileExpr expr)
170           let myprec = 10 -- application precedence. TODO Infix constructors
171           let txt = unsafeCoerce# txt_
172           if not (null txt) then
173             return $ Just $ cparen (prec >= myprec && needsParens txt)
174                                    (text txt)
175            else return Nothing
176         `gfinally` do
177           setSession hsc_env
178           GHC.setSessionDynFlags dflags
179  cPprShowable prec NewtypeWrap{ty=new_ty,wrapped_term=t} = 
180      cPprShowable prec t{ty=new_ty}
181  cPprShowable _ _ = return Nothing
182
183  needsParens ('"':_) = False   -- some simple heuristics to see whether parens
184                                -- are redundant in an arbitrary Show output
185  needsParens ('(':_) = False
186  needsParens txt = ' ' `elem` txt
187
188
189  bindToFreshName hsc_env ty userName = do
190    name <- newGrimName userName
191    let id       = AnId $ mkVanillaGlobal name ty
192        new_ic   = extendInteractiveContext (hsc_IC hsc_env) [id]
193    return (hsc_env {hsc_IC = new_ic }, name)
194
195--    Create new uniques and give them sequentially numbered names
196newGrimName :: MonadIO m => String -> m Name
197newGrimName userName  = do
198    us <- liftIO $ mkSplitUniqSupply 'b'
199    let unique  = uniqFromSupply us
200        occname = mkOccName varName userName
201        name    = mkInternalName unique occname noSrcSpan
202    return name
203
204pprTypeAndContents :: GhcMonad m => Id -> m SDoc
205pprTypeAndContents id = do
206  dflags  <- GHC.getSessionDynFlags
207  let pefas     = dopt Opt_PrintExplicitForalls dflags
208      pcontents = dopt Opt_PrintBindContents dflags
209      pprdId    = (pprTyThing pefas . AnId) id
210  if pcontents
211    then do
212      let depthBound = 100
213      -- If the value is an exception, make sure we catch it and
214      -- show the exception, rather than propagating the exception out.
215      e_term <- gtry $ GHC.obtainTermFromId depthBound False id
216      docs_term <- case e_term of
217                      Right term -> showTerm term
218                      Left  exn  -> return (text "*** Exception:" <+>
219                                            text (show (exn :: SomeException)))
220      return $ pprdId <+> equals <+> docs_term
221    else return pprdId
222
223--------------------------------------------------------------
224-- Utils
225
226traceOptIf :: GhcMonad m => DynFlag -> SDoc -> m ()
227traceOptIf flag doc = do
228  dflags <- GHC.getSessionDynFlags
229  when (dopt flag dflags) $ liftIO $ printForUser stderr alwaysQualify doc
Note: See TracBrowser for help on using the browser.