1 -----------------------------------------------------------------------------
3 -- GHC Interactive support for inspecting arbitrary closures at runtime
5 -- Pepe Iborra (supported by Google SoC) 2006
7 -----------------------------------------------------------------------------
9 module RtClosureInspect(
10 cvObtainTerm, -- :: HscEnv -> Int -> Bool -> Maybe Type -> HValue -> IO Term
15 isTerm, isSuspension, isPrim, isFun, isFunLike, isNewtypeWrap,
16 isFullyEvaluated, isFullyEvaluatedTerm,
17 termType, mapTermType, termTyVars,
18 foldTerm, TermFold(..), foldTermM, TermFoldM(..), idTermFold,
19 pprTerm, cPprTerm, cPprTermBase, CustomTermPrinter,
23 Closure(..), getClosureData, ClosureType(..), isConstr, isIndirection,
28 #include "HsVersions.h"
30 import ByteCodeItbls ( StgInfoTable )
31 import qualified ByteCodeItbls as BCI( StgInfoTable(..) )
37 import TypeRep -- I know I know, this is cheating
59 import Constants ( wORD_SIZE )
61 import GHC.Arr ( Array(..) )
64 #if __GLASGOW_HASKELL__ >= 611
65 import GHC.IO ( IO(..) )
67 import GHC.IOBase ( IO(..) )
72 import Data.Array.Base
75 import qualified Data.Sequence as Seq
77 import Data.Sequence hiding (null, length, index, take, drop, splitAt, reverse)
79 import System.IO.Unsafe
82 ---------------------------------------------
83 -- * A representation of semi evaluated Terms
84 ---------------------------------------------
86 data Term = Term { ty :: RttiType
87 , dc :: Either String DataCon
88 -- Carries a text representation if the datacon is
89 -- not exported by the .hi file, which is the case
90 -- for private constructors in -O0 compiled libraries
92 , subTerms :: [Term] }
94 | Prim { ty :: RttiType
97 | Suspension { ctype :: ClosureType
100 , bound_to :: Maybe Name -- Useful for printing
102 | NewtypeWrap{ -- At runtime there are no newtypes, and hence no
103 -- newtype constructors. A NewtypeWrap is just a
104 -- made-up tag saying "heads up, there used to be
105 -- a newtype constructor here".
107 , dc :: Either String DataCon
108 , wrapped_term :: Term }
109 | RefWrap { -- The contents of a reference
111 , wrapped_term :: Term }
113 isTerm, isSuspension, isPrim, isFun, isFunLike, isNewtypeWrap :: Term -> Bool
116 isSuspension Suspension{} = True
117 isSuspension _ = False
120 isNewtypeWrap NewtypeWrap{} = True
121 isNewtypeWrap _ = False
123 isFun Suspension{ctype=Fun} = True
126 isFunLike s@Suspension{ty=ty} = isFun s || isFunTy ty
129 termType :: Term -> RttiType
132 isFullyEvaluatedTerm :: Term -> Bool
133 isFullyEvaluatedTerm Term {subTerms=tt} = all isFullyEvaluatedTerm tt
134 isFullyEvaluatedTerm Prim {} = True
135 isFullyEvaluatedTerm NewtypeWrap{wrapped_term=t} = isFullyEvaluatedTerm t
136 isFullyEvaluatedTerm RefWrap{wrapped_term=t} = isFullyEvaluatedTerm t
137 isFullyEvaluatedTerm _ = False
139 instance Outputable (Term) where
140 ppr t | Just doc <- cPprTerm cPprTermBase t = doc
141 | otherwise = panic "Outputable Term instance"
143 -------------------------------------------------------------------------
144 -- Runtime Closure Datatype and functions for retrieving closure related stuff
145 -------------------------------------------------------------------------
146 data ClosureType = Constr
159 data Closure = Closure { tipe :: ClosureType
161 , infoTable :: StgInfoTable
162 , ptrs :: Array Int HValue
166 instance Outputable ClosureType where
169 #include "../includes/ClosureTypes.h"
171 aP_CODE, pAP_CODE :: Int
177 getClosureData :: a -> IO Closure
179 case unpackClosure# a of
180 (# iptr, ptrs, nptrs #) -> do
182 | ghciTablesNextToCode =
185 -- the info pointer we get back from unpackClosure#
186 -- is to the beginning of the standard info table,
187 -- but the Storable instance for info tables takes
188 -- into account the extra entry pointer when
189 -- !ghciTablesNextToCode, so we must adjust here:
190 Ptr iptr `plusPtr` negate wORD_SIZE
192 let tipe = readCType (BCI.tipe itbl)
193 elems = fromIntegral (BCI.ptrs itbl)
194 ptrsList = Array 0 (elems - 1) elems ptrs
195 nptrs_data = [W# (indexWordArray# nptrs i)
196 | I# i <- [0.. fromIntegral (BCI.nptrs itbl)] ]
197 ASSERT(elems >= 0) return ()
199 return (Closure tipe (Ptr iptr) itbl ptrsList nptrs_data)
201 readCType :: Integral a => a -> ClosureType
203 | i >= CONSTR && i <= CONSTR_NOCAF_STATIC = Constr
204 | i >= FUN && i <= FUN_STATIC = Fun
205 | i >= THUNK && i < THUNK_SELECTOR = Thunk i'
206 | i == THUNK_SELECTOR = ThunkSelector
207 | i == BLACKHOLE = Blackhole
208 | i >= IND && i <= IND_STATIC = Indirection i'
211 | i' == pAP_CODE = PAP
212 | i == MUT_VAR_CLEAN || i == MUT_VAR_DIRTY= MutVar i'
213 | i == MVAR_CLEAN || i == MVAR_DIRTY = MVar i'
214 | otherwise = Other i'
215 where i' = fromIntegral i
217 isConstr, isIndirection, isThunk :: ClosureType -> Bool
218 isConstr Constr = True
221 isIndirection (Indirection _) = True
222 isIndirection _ = False
224 isThunk (Thunk _) = True
225 isThunk ThunkSelector = True
229 isFullyEvaluated :: a -> IO Bool
230 isFullyEvaluated a = do
231 closure <- getClosureData a
233 Constr -> do are_subs_evaluated <- amapM isFullyEvaluated (ptrs closure)
234 return$ and are_subs_evaluated
236 where amapM f = sequence . amap' f
238 -- TODO: Fix it. Probably the otherwise case is failing, trace/debug it
240 unsafeDeepSeq :: a -> b -> b
241 unsafeDeepSeq = unsafeDeepSeq1 2
242 where unsafeDeepSeq1 0 a b = seq a $! b
243 unsafeDeepSeq1 i a b -- 1st case avoids infinite loops for non reducible thunks
244 | not (isConstr tipe) = seq a $! unsafeDeepSeq1 (i-1) a b
245 -- | unsafePerformIO (isFullyEvaluated a) = b
246 | otherwise = case unsafePerformIO (getClosureData a) of
247 closure -> foldl' (flip unsafeDeepSeq) b (ptrs closure)
248 where tipe = unsafePerformIO (getClosureType a)
251 -----------------------------------
252 -- * Traversals for Terms
253 -----------------------------------
254 type TermProcessor a b = RttiType -> Either String DataCon -> HValue -> [a] -> b
256 data TermFold a = TermFold { fTerm :: TermProcessor a a
257 , fPrim :: RttiType -> [Word] -> a
258 , fSuspension :: ClosureType -> RttiType -> HValue
260 , fNewtypeWrap :: RttiType -> Either String DataCon
262 , fRefWrap :: RttiType -> a -> a
267 TermFoldM {fTermM :: TermProcessor a (m a)
268 , fPrimM :: RttiType -> [Word] -> m a
269 , fSuspensionM :: ClosureType -> RttiType -> HValue
271 , fNewtypeWrapM :: RttiType -> Either String DataCon
273 , fRefWrapM :: RttiType -> a -> m a
276 foldTerm :: TermFold a -> Term -> a
277 foldTerm tf (Term ty dc v tt) = fTerm tf ty dc v (map (foldTerm tf) tt)
278 foldTerm tf (Prim ty v ) = fPrim tf ty v
279 foldTerm tf (Suspension ct ty v b) = fSuspension tf ct ty v b
280 foldTerm tf (NewtypeWrap ty dc t) = fNewtypeWrap tf ty dc (foldTerm tf t)
281 foldTerm tf (RefWrap ty t) = fRefWrap tf ty (foldTerm tf t)
284 foldTermM :: Monad m => TermFoldM m a -> Term -> m a
285 foldTermM tf (Term ty dc v tt) = mapM (foldTermM tf) tt >>= fTermM tf ty dc v
286 foldTermM tf (Prim ty v ) = fPrimM tf ty v
287 foldTermM tf (Suspension ct ty v b) = fSuspensionM tf ct ty v b
288 foldTermM tf (NewtypeWrap ty dc t) = foldTermM tf t >>= fNewtypeWrapM tf ty dc
289 foldTermM tf (RefWrap ty t) = foldTermM tf t >>= fRefWrapM tf ty
291 idTermFold :: TermFold Term
292 idTermFold = TermFold {
295 fSuspension = Suspension,
296 fNewtypeWrap = NewtypeWrap,
300 mapTermType :: (RttiType -> Type) -> Term -> Term
301 mapTermType f = foldTerm idTermFold {
302 fTerm = \ty dc hval tt -> Term (f ty) dc hval tt,
303 fSuspension = \ct ty hval n ->
304 Suspension ct (f ty) hval n,
305 fNewtypeWrap= \ty dc t -> NewtypeWrap (f ty) dc t,
306 fRefWrap = \ty t -> RefWrap (f ty) t}
308 mapTermTypeM :: Monad m => (RttiType -> m Type) -> Term -> m Term
309 mapTermTypeM f = foldTermM TermFoldM {
310 fTermM = \ty dc hval tt -> f ty >>= \ty' -> return $ Term ty' dc hval tt,
311 fPrimM = (return.) . Prim,
312 fSuspensionM = \ct ty hval n ->
313 f ty >>= \ty' -> return $ Suspension ct ty' hval n,
314 fNewtypeWrapM= \ty dc t -> f ty >>= \ty' -> return $ NewtypeWrap ty' dc t,
315 fRefWrapM = \ty t -> f ty >>= \ty' -> return $ RefWrap ty' t}
317 termTyVars :: Term -> TyVarSet
318 termTyVars = foldTerm TermFold {
319 fTerm = \ty _ _ tt ->
320 tyVarsOfType ty `plusVarEnv` concatVarEnv tt,
321 fSuspension = \_ ty _ _ -> tyVarsOfType ty,
322 fPrim = \ _ _ -> emptyVarEnv,
323 fNewtypeWrap= \ty _ t -> tyVarsOfType ty `plusVarEnv` t,
324 fRefWrap = \ty t -> tyVarsOfType ty `plusVarEnv` t}
325 where concatVarEnv = foldr plusVarEnv emptyVarEnv
327 ----------------------------------
328 -- Pretty printing of terms
329 ----------------------------------
331 type Precedence = Int
332 type TermPrinter = Precedence -> Term -> SDoc
333 type TermPrinterM m = Precedence -> Term -> m SDoc
335 app_prec,cons_prec, max_prec ::Int
338 cons_prec = 5 -- TODO Extract this info from GHC itself
340 pprTerm :: TermPrinter -> TermPrinter
341 pprTerm y p t | Just doc <- pprTermM (\p -> Just . y p) p t = doc
342 pprTerm _ _ _ = panic "pprTerm"
344 pprTermM, ppr_termM, pprNewtypeWrap :: Monad m => TermPrinterM m -> TermPrinterM m
345 pprTermM y p t = pprDeeper `liftM` ppr_termM y p t
347 ppr_termM y p Term{dc=Left dc_tag, subTerms=tt} = do
348 tt_docs <- mapM (y app_prec) tt
349 return$ cparen (not(null tt) && p >= app_prec) (text dc_tag <+> pprDeeperList fsep tt_docs)
351 ppr_termM y p Term{dc=Right dc, subTerms=tt}
352 {- | dataConIsInfix dc, (t1:t2:tt') <- tt --TODO fixity
353 = parens (ppr_term1 True t1 <+> ppr dc <+> ppr_term1 True ppr t2)
354 <+> hsep (map (ppr_term1 True) tt)
355 -} -- TODO Printing infix constructors properly
356 | null tt = return$ ppr dc
358 tt_docs <- mapM (y app_prec) tt
359 return$ cparen (p >= app_prec) (ppr dc <+> pprDeeperList fsep tt_docs)
361 ppr_termM y p t@NewtypeWrap{} = pprNewtypeWrap y p t
362 ppr_termM y p RefWrap{wrapped_term=t} = do
363 contents <- y app_prec t
364 return$ cparen (p >= app_prec) (text "GHC.Prim.MutVar#" <+> contents)
365 -- The constructor name is wired in here ^^^ for the sake of simplicity.
366 -- I don't think mutvars are going to change in a near future.
367 -- In any case this is solely a presentation matter: MutVar# is
368 -- a datatype with no constructors, implemented by the RTS
369 -- (hence there is no way to obtain a datacon and print it).
370 ppr_termM _ _ t = ppr_termM1 t
373 ppr_termM1 :: Monad m => Term -> m SDoc
374 ppr_termM1 Prim{value=words, ty=ty} =
375 return$ text$ repPrim (tyConAppTyCon ty) words
376 ppr_termM1 Suspension{ty=ty, bound_to=Nothing} =
377 return (char '_' <+> ifPprDebug (text "::" <> ppr ty))
378 ppr_termM1 Suspension{ty=ty, bound_to=Just n}
379 -- | Just _ <- splitFunTy_maybe ty = return$ ptext (sLit("<function>")
380 | otherwise = return$ parens$ ppr n <> text "::" <> ppr ty
381 ppr_termM1 Term{} = panic "ppr_termM1 - Term"
382 ppr_termM1 RefWrap{} = panic "ppr_termM1 - RefWrap"
383 ppr_termM1 NewtypeWrap{} = panic "ppr_termM1 - NewtypeWrap"
385 pprNewtypeWrap y p NewtypeWrap{ty=ty, wrapped_term=t}
386 | Just (tc,_) <- tcSplitTyConApp_maybe ty
387 , ASSERT(isNewTyCon tc) True
388 , Just new_dc <- tyConSingleDataCon_maybe tc = do
389 real_term <- y max_prec t
390 return$ cparen (p >= app_prec) (ppr new_dc <+> real_term)
391 pprNewtypeWrap _ _ _ = panic "pprNewtypeWrap"
393 -------------------------------------------------------
394 -- Custom Term Pretty Printers
395 -------------------------------------------------------
397 -- We can want to customize the representation of a
398 -- term depending on its type.
399 -- However, note that custom printers have to work with
400 -- type representations, instead of directly with types.
401 -- We cannot use type classes here, unless we employ some
402 -- typerep trickery (e.g. Weirich's RepLib tricks),
403 -- which I didn't. Therefore, this code replicates a lot
404 -- of what type classes provide for free.
406 type CustomTermPrinter m = TermPrinterM m
407 -> [Precedence -> Term -> (m (Maybe SDoc))]
409 -- | Takes a list of custom printers with a explicit recursion knot and a term,
410 -- and returns the output of the first succesful printer, or the default printer
411 cPprTerm :: Monad m => CustomTermPrinter m -> Term -> m SDoc
412 cPprTerm printers_ = go 0 where
413 printers = printers_ go
415 let default_ = Just `liftM` pprTermM go prec t
416 mb_customDocs = [pp prec t | pp <- printers] ++ [default_]
417 Just doc <- firstJustM mb_customDocs
418 return$ cparen (prec>app_prec+1) doc
420 firstJustM (mb:mbs) = mb >>= maybe (firstJustM mbs) (return . Just)
421 firstJustM [] = return Nothing
423 -- Default set of custom printers. Note that the recursion knot is explicit
424 cPprTermBase :: Monad m => CustomTermPrinter m
426 [ ifTerm (isTupleTy.ty) (\_p -> liftM (parens . hcat . punctuate comma)
429 , ifTerm (\t -> isTyCon listTyCon (ty t) && subTerms t `lengthIs` 2)
430 (\ p Term{subTerms=[h,t]} -> doList p h t)
431 , ifTerm (isTyCon intTyCon . ty) (coerceShow$ \(a::Int)->a)
432 , ifTerm (isTyCon charTyCon . ty) (coerceShow$ \(a::Char)->a)
433 , ifTerm (isTyCon floatTyCon . ty) (coerceShow$ \(a::Float)->a)
434 , ifTerm (isTyCon doubleTyCon . ty) (coerceShow$ \(a::Double)->a)
435 , ifTerm (isIntegerTy . ty) (coerceShow$ \(a::Integer)->a)
437 where ifTerm pred f prec t@Term{}
438 | pred t = Just `liftM` f prec t
439 ifTerm _ _ _ _ = return Nothing
441 isIntegerTy ty = fromMaybe False $ do
442 (tc,_) <- tcSplitTyConApp_maybe ty
443 return (tyConName tc == integerTyConName)
445 isTupleTy ty = fromMaybe False $ do
446 (tc,_) <- tcSplitTyConApp_maybe ty
447 return (isBoxedTupleTyCon tc)
449 isTyCon a_tc ty = fromMaybe False $ do
450 (tc,_) <- tcSplitTyConApp_maybe ty
453 coerceShow f _p = return . text . show . f . unsafeCoerce# . val
455 --Note pprinting of list terms is not lazy
457 let elems = h : getListTerms t
458 isConsLast = not(termType(last elems) `coreEqType` termType h)
459 print_elems <- mapM (y cons_prec) elems
460 return$ if isConsLast
461 then cparen (p >= cons_prec)
463 . punctuate (space<>colon)
465 else brackets (pprDeeperList fcat$
466 punctuate comma print_elems)
468 where getListTerms Term{subTerms=[h,t]} = h : getListTerms t
469 getListTerms Term{subTerms=[]} = []
470 getListTerms t@Suspension{} = [t]
471 getListTerms t = pprPanic "getListTerms" (ppr t)
474 repPrim :: TyCon -> [Word] -> String
475 repPrim t = rep where
477 | t == charPrimTyCon = show (build x :: Char)
478 | t == intPrimTyCon = show (build x :: Int)
479 | t == wordPrimTyCon = show (build x :: Word)
480 | t == floatPrimTyCon = show (build x :: Float)
481 | t == doublePrimTyCon = show (build x :: Double)
482 | t == int32PrimTyCon = show (build x :: Int32)
483 | t == word32PrimTyCon = show (build x :: Word32)
484 | t == int64PrimTyCon = show (build x :: Int64)
485 | t == word64PrimTyCon = show (build x :: Word64)
486 | t == addrPrimTyCon = show (nullPtr `plusPtr` build x)
487 | t == stablePtrPrimTyCon = "<stablePtr>"
488 | t == stableNamePrimTyCon = "<stableName>"
489 | t == statePrimTyCon = "<statethread>"
490 | t == realWorldTyCon = "<realworld>"
491 | t == threadIdPrimTyCon = "<ThreadId>"
492 | t == weakPrimTyCon = "<Weak>"
493 | t == arrayPrimTyCon = "<array>"
494 | t == byteArrayPrimTyCon = "<bytearray>"
495 | t == mutableArrayPrimTyCon = "<mutableArray>"
496 | t == mutableByteArrayPrimTyCon = "<mutableByteArray>"
497 | t == mutVarPrimTyCon= "<mutVar>"
498 | t == mVarPrimTyCon = "<mVar>"
499 | t == tVarPrimTyCon = "<tVar>"
500 | otherwise = showSDoc (char '<' <> ppr t <> char '>')
501 where build ww = unsafePerformIO $ withArray ww (peek . castPtr)
502 -- This ^^^ relies on the representation of Haskell heap values being
503 -- the same as in a C array.
505 -----------------------------------
506 -- Type Reconstruction
507 -----------------------------------
509 Type Reconstruction is type inference done on heap closures.
510 The algorithm walks the heap generating a set of equations, which
511 are solved with syntactic unification.
512 A type reconstruction equation looks like:
514 <datacon reptype> = <actual heap contents>
516 The full equation set is generated by traversing all the subterms, starting
519 The only difficult part is that newtypes are only found in the lhs of equations.
520 Right hand sides are missing them. We can either (a) drop them from the lhs, or
521 (b) reconstruct them in the rhs when possible.
523 The function congruenceNewtypes takes a shot at (b)
527 -- A (non-mutable) tau type containing
528 -- existentially quantified tyvars.
529 -- (since GHC type language currently does not support
530 -- existentials, we leave these variables unquantified)
533 -- An incomplete type as stored in GHCi:
534 -- no polymorphism: no quantifiers & all tyvars are skolem.
538 -- The Type Reconstruction monad
539 --------------------------------
542 runTR :: HscEnv -> TR a -> IO a
543 runTR hsc_env thing = do
544 mb_val <- runTR_maybe hsc_env thing
546 Nothing -> error "unable to :print the term"
549 runTR_maybe :: HscEnv -> TR a -> IO (Maybe a)
550 runTR_maybe hsc_env = fmap snd . initTc hsc_env HsSrcFile False iNTERACTIVE
552 traceTR :: SDoc -> TR ()
553 traceTR = liftTcM . traceOptTcRn Opt_D_dump_rtti
556 -- Semantically different to recoverM in TcRnMonad
557 -- recoverM retains the errors in the first action,
558 -- whereas recoverTc here does not
559 recoverTR :: TR a -> TR a -> TR a
560 recoverTR recover thing = do
561 (_,mb_res) <- tryTcErrs thing
564 Just res -> return res
567 trIO = liftTcM . liftIO
569 liftTcM :: TcM a -> TR a
572 newVar :: Kind -> TR TcType
573 newVar = liftTcM . liftM mkTyVarTy . newBoxyTyVar
575 -- | Returns the instantiated type scheme ty', and the substitution sigma
576 -- such that sigma(ty') = ty
577 instScheme :: Type -> TR (TcType, TvSubst)
578 instScheme ty = liftTcM$ do
579 (tvs, _, _) <- tcInstType return ty
580 (tvs',_,ty') <- tcInstType (mapM tcInstTyVar) ty
581 return (ty', zipTopTvSubst tvs' (mkTyVarTys tvs))
583 -- Adds a constraint of the form t1 == t2
584 -- t1 is expected to come from walking the heap
585 -- t2 is expected to come from a datacon signature
586 -- Before unification, congruenceNewtypes needs to
588 addConstraint :: TcType -> TcType -> TR ()
589 addConstraint actual expected = do
590 traceTR (text "add constraint:" <+> fsep [ppr actual, equals, ppr expected])
591 recoverTR (traceTR $ fsep [text "Failed to unify", ppr actual,
592 text "with", ppr expected])
593 (congruenceNewtypes actual expected >>=
594 (getLIE . uncurry boxyUnify) >> return ())
595 -- TOMDO: what about the coercion?
596 -- we should consider family instances
599 -- Type & Term reconstruction
600 ------------------------------
601 cvObtainTerm :: HscEnv -> Int -> Bool -> RttiType -> HValue -> IO Term
602 cvObtainTerm hsc_env max_depth force old_ty hval = runTR hsc_env $ do
603 -- we quantify existential tyvars as universal,
604 -- as this is needed to be able to manipulate
606 let sigma_old_ty = sigmaType old_ty
607 traceTR (text "Term reconstruction started with initial type " <> ppr old_ty)
609 if isMonomorphic sigma_old_ty
611 new_ty <- go max_depth sigma_old_ty sigma_old_ty hval >>= zonkTerm
612 return $ fixFunDictionaries $ expandNewtypes new_ty
614 (old_ty', rev_subst) <- instScheme sigma_old_ty
615 my_ty <- newVar argTypeKind
616 when (check1 sigma_old_ty) (traceTR (text "check1 passed") >>
617 addConstraint my_ty old_ty')
618 term <- go max_depth my_ty sigma_old_ty hval
619 zterm <- zonkTerm term
620 let new_ty = termType zterm
621 if isMonomorphic new_ty || check2 (sigmaType new_ty) sigma_old_ty
623 traceTR (text "check2 passed")
624 addConstraint (termType term) old_ty'
625 zterm' <- zonkTerm term
626 return ((fixFunDictionaries . expandNewtypes . mapTermType (substTy rev_subst)) zterm')
628 traceTR (text "check2 failed" <+> parens
629 (ppr zterm <+> text "::" <+> ppr new_ty))
630 -- we have unsound types. Replace constructor types in
631 -- subterms with tyvars
632 zterm' <- mapTermTypeM
633 (\ty -> case tcSplitTyConApp_maybe ty of
634 Just (tc, _:_) | tc /= funTyCon
635 -> newVar argTypeKind
639 traceTR (text "Term reconstruction completed." $$
640 text "Term obtained: " <> ppr term $$
641 text "Type obtained: " <> ppr (termType term))
644 go :: Int -> Type -> Type -> HValue -> TcM Term
645 go max_depth _ _ _ | seq max_depth False = undefined
646 go 0 my_ty _old_ty a = do
647 traceTR (text "Gave up reconstructing a term after" <>
648 int max_depth <> text " steps")
649 clos <- trIO $ getClosureData a
650 return (Suspension (tipe clos) my_ty a Nothing)
651 go max_depth my_ty old_ty a = do
652 let monomorphic = not(isTyVarTy my_ty)
653 -- This ^^^ is a convention. The ancestor tests for
654 -- monomorphism and passes a type instead of a tv
655 clos <- trIO $ getClosureData a
657 -- Thunks we may want to force
658 -- NB. this won't attempt to force a BLACKHOLE. Even with :force, we never
659 -- force blackholes, because it would almost certainly result in deadlock,
660 -- and showing the '_' is more useful.
661 t | isThunk t && force -> traceTR (text "Forcing a " <> text (show t)) >>
662 seq a (go (pred max_depth) my_ty old_ty a)
663 -- We always follow indirections
664 Indirection i -> do traceTR (text "Following an indirection" <> parens (int i) )
665 go max_depth my_ty old_ty $! (ptrs clos ! 0)
666 -- We also follow references
667 MutVar _ | Just (tycon,[world,contents_ty]) <- tcSplitTyConApp_maybe old_ty
669 -- Deal with the MutVar# primitive
670 -- It does not have a constructor at all,
671 -- so we simulate the following one
672 -- MutVar# :: contents_ty -> MutVar# s contents_ty
673 traceTR (text "Following a MutVar")
674 contents_tv <- newVar liftedTypeKind
675 contents <- trIO$ IO$ \w -> readMutVar# (unsafeCoerce# a) w
676 ASSERT(isUnliftedTypeKind $ typeKind my_ty) return ()
677 (mutvar_ty,_) <- instScheme $ sigmaType $ mkFunTy
678 contents_ty (mkTyConApp tycon [world,contents_ty])
679 addConstraint (mkFunTy contents_tv my_ty) mutvar_ty
680 x <- go (pred max_depth) contents_tv contents_ty contents
681 return (RefWrap my_ty x)
683 -- The interesting case
685 traceTR (text "entering a constructor " <>
687 then parens (text "already monomorphic: " <> ppr my_ty)
688 else Outputable.empty)
689 Right dcname <- dataConInfoPtrToName (infoPtr clos)
690 (_,mb_dc) <- tryTcErrs (tcLookupDataCon dcname)
692 Nothing -> do -- This can happen for private constructors compiled -O0
693 -- where the .hi descriptor does not export them
694 -- In such case, we return a best approximation:
695 -- ignore the unpointed args, and recover the pointeds
696 -- This preserves laziness, and should be safe.
697 let tag = showSDoc (ppr dcname)
698 vars <- replicateM (length$ elems$ ptrs clos)
699 (newVar (liftedTypeKind))
700 subTerms <- sequence [appArr (go (pred max_depth) tv tv) (ptrs clos) i
701 | (i, tv) <- zip [0..] vars]
702 return (Term my_ty (Left ('<' : tag ++ ">")) a subTerms)
704 let subTtypes = matchSubTypes dc old_ty
705 subTermTvs <- mapMif (not . isMonomorphic)
706 (\t -> newVar (typeKind t))
708 let (subTermsP, subTermsNP) = partition (\(ty,_) -> isLifted ty
710 (zip subTtypes subTermTvs)
711 (subTtypesP, subTermTvsP ) = unzip subTermsP
712 (subTtypesNP, _subTermTvsNP) = unzip subTermsNP
714 -- When we already have all the information, avoid solving
715 -- unnecessary constraints. Propagation of type information
716 -- to subterms is already being done via matching.
717 when (not monomorphic) $ do
718 let myType = mkFunTys subTermTvs my_ty
719 (signatureType,_) <- instScheme (mydataConType dc)
720 -- It is vital for newtype reconstruction that the unification step
721 -- is done right here, _before_ the subterms are RTTI reconstructed
722 addConstraint myType signatureType
723 subTermsP <- sequence
724 [ appArr (go (pred max_depth) tv t) (ptrs clos) i
725 | (i,tv,t) <- zip3 [0..] subTermTvsP subTtypesP]
726 let unboxeds = extractUnboxed subTtypesNP clos
727 subTermsNP = map (uncurry Prim) (zip subTtypesNP unboxeds)
728 subTerms = reOrderTerms subTermsP subTermsNP subTtypes
729 return (Term my_ty (Right dc) a subTerms)
730 -- The otherwise case: can be a Thunk,AP,PAP,etc.
732 return (Suspension tipe_clos my_ty a Nothing)
735 | ty' <- repType ty -- look through newtypes
736 , Just (tc,ty_args) <- tcSplitTyConApp_maybe ty'
737 , dc `elem` tyConDataCons tc
738 -- It is necessary to check that dc is actually a constructor for tycon tc,
739 -- because it may be the case that tc is a recursive newtype and tcSplitTyConApp
740 -- has not removed it. In that case, we happily give up and don't match
741 = myDataConInstArgTys dc ty_args
742 | otherwise = dataConRepArgTys dc
744 -- put together pointed and nonpointed subterms in the
746 reOrderTerms _ _ [] = []
747 reOrderTerms pointed unpointed (ty:tys)
748 | isLifted ty || isRefType ty
749 = ASSERT2(not(null pointed)
750 , ptext (sLit "reOrderTerms") $$
751 (ppr pointed $$ ppr unpointed))
752 let (t:tt) = pointed in t : reOrderTerms tt unpointed tys
753 | otherwise = ASSERT2(not(null unpointed)
754 , ptext (sLit "reOrderTerms") $$
755 (ppr pointed $$ ppr unpointed))
756 let (t:tt) = unpointed in t : reOrderTerms pointed tt tys
758 -- insert NewtypeWraps around newtypes
759 expandNewtypes = foldTerm idTermFold { fTerm = worker } where
761 | Just (tc, args) <- tcSplitTyConApp_maybe ty
763 , wrapped_type <- newTyConInstRhs tc args
764 , Just dc' <- tyConSingleDataCon_maybe tc
765 , t' <- worker wrapped_type dc hval tt
766 = NewtypeWrap ty (Right dc') t'
767 | otherwise = Term ty dc hval tt
770 -- Avoid returning types where predicates have been expanded to dictionaries.
771 fixFunDictionaries = foldTerm idTermFold {fSuspension = worker} where
772 worker ct ty hval n | isFunTy ty = Suspension ct (dictsView ty) hval n
773 | otherwise = Suspension ct ty hval n
776 -- Fast, breadth-first Type reconstruction
777 ------------------------------------------
778 cvReconstructType :: HscEnv -> Int -> GhciType -> HValue -> IO (Maybe Type)
779 cvReconstructType hsc_env max_depth old_ty hval = runTR_maybe hsc_env $ do
780 traceTR (text "RTTI started with initial type " <> ppr old_ty)
781 let sigma_old_ty = sigmaType old_ty
783 if isMonomorphic sigma_old_ty
786 (old_ty', rev_subst) <- instScheme sigma_old_ty
787 my_ty <- newVar argTypeKind
788 when (check1 sigma_old_ty) (traceTR (text "check1 passed") >>
789 addConstraint my_ty old_ty')
790 search (isMonomorphic `fmap` zonkTcType my_ty)
792 (Seq.singleton (my_ty, hval))
794 new_ty <- zonkTcType my_ty
795 if isMonomorphic new_ty || check2 (sigmaType new_ty) sigma_old_ty
797 traceTR (text "check2 passed")
798 addConstraint my_ty old_ty'
799 new_ty' <- zonkTcType my_ty
800 return (substTy rev_subst new_ty')
801 else traceTR (text "check2 failed" <+> parens (ppr new_ty)) >>
803 traceTR (text "RTTI completed. Type obtained:" <+> ppr new_ty)
806 -- search :: m Bool -> ([a] -> [a] -> [a]) -> [a] -> m ()
807 search _ _ _ 0 = traceTR (text "Failed to reconstruct a type after " <>
808 int max_depth <> text " steps")
809 search stop expand l d =
812 x :< xx -> unlessM stop $ do
814 search stop expand (xx `mappend` Seq.fromList new) $! (pred d)
816 -- returns unification tasks,since we are going to want a breadth-first search
817 go :: Type -> HValue -> TR [(Type, HValue)]
819 clos <- trIO $ getClosureData a
821 Indirection _ -> go my_ty $! (ptrs clos ! 0)
823 contents <- trIO$ IO$ \w -> readMutVar# (unsafeCoerce# a) w
824 tv' <- newVar liftedTypeKind
825 world <- newVar liftedTypeKind
826 addConstraint my_ty (mkTyConApp mutVarPrimTyCon [world,tv'])
827 return [(tv', contents)]
829 Right dcname <- dataConInfoPtrToName (infoPtr clos)
830 (_,mb_dc) <- tryTcErrs (tcLookupDataCon dcname)
833 -- TODO: Check this case
834 forM [0..length (elems $ ptrs clos)] $ \i -> do
835 tv <- newVar liftedTypeKind
836 return$ appArr (\e->(tv,e)) (ptrs clos) i
839 subTtypes <- mapMif (not . isMonomorphic)
840 (\t -> newVar (typeKind t))
841 (dataConRepArgTys dc)
843 -- It is vital for newtype reconstruction that the unification step
844 -- is done right here, _before_ the subterms are RTTI reconstructed
845 let myType = mkFunTys subTtypes my_ty
846 (signatureType,_) <- instScheme(mydataConType dc)
847 addConstraint myType signatureType
848 return $ [ appArr (\e->(t,e)) (ptrs clos) i
849 | (i,t) <- zip [0..] (filter (isLifted |.| isRefType) subTtypes)]
852 -- Compute the difference between a base type and the type found by RTTI
853 -- improveType <base_type> <rtti_type>
854 -- The types can contain skolem type variables, which need to be treated as normal vars.
855 -- In particular, we want them to unify with things.
856 improveRTTIType :: HscEnv -> RttiType -> RttiType -> IO (Maybe TvSubst)
857 improveRTTIType hsc_env _ty rtti_ty = runTR_maybe hsc_env $ do
858 traceTR (text "improveRttiType" <+> fsep [ppr _ty, ppr rtti_ty])
859 (ty_tvs, _, _) <- tcInstType return ty
860 (ty_tvs', _, ty') <- tcInstType (mapM tcInstTyVar) ty
861 (_, _, rtti_ty') <- tcInstType (mapM tcInstTyVar) (sigmaType rtti_ty)
862 getLIE(boxyUnify rtti_ty' ty')
863 tvs1_contents <- zonkTcTyVars ty_tvs'
864 let subst = (uncurry zipTopTvSubst . unzip)
865 [(tv,ty) | (tv,ty) <- zip ty_tvs tvs1_contents
866 , getTyVar_maybe ty /= Just tv
867 --, not(isTyVarTy ty)
870 where ty = sigmaType _ty
872 myDataConInstArgTys :: DataCon -> [Type] -> [Type]
873 myDataConInstArgTys dc args
874 | null (dataConExTyVars dc) && null (dataConEqTheta dc) = dataConInstArgTys dc args
875 | otherwise = dataConRepArgTys dc
877 mydataConType :: DataCon -> Type
878 -- ^ Custom version of DataCon.dataConUserType where we
879 -- - remove the equality constraints
880 -- - use the representation types for arguments, including dictionaries
881 -- - keep the original result type
883 = mkForAllTys ((univ_tvs `minusList` map fst eq_spec) ++ ex_tvs) $
886 where univ_tvs = dataConUnivTyVars dc
887 ex_tvs = dataConExTyVars dc
888 eq_spec = dataConEqSpec dc
890 PredTy p -> predTypeRep p
892 | a <- dataConRepArgTys dc]
893 res_ty = dataConOrigResTy dc
895 isRefType :: Type -> Bool
897 | Just (tc, _) <- tcSplitTyConApp_maybe ty' = isRefTyCon tc
899 where ty'= repType ty
901 isRefTyCon :: TyCon -> Bool
902 isRefTyCon tc = tc `elem` [mutVarPrimTyCon, mVarPrimTyCon, tVarPrimTyCon]
907 This is not formalized anywhere, so hold to your seats!
908 RTTI in the presence of newtypes can be a tricky and unsound business.
912 Suppose we are doing RTTI for a partially evaluated
913 closure t, the real type of which is t :: MkT Int, for
915 newtype MkT a = MkT [Maybe a]
917 The table below shows the results of RTTI and the improvement
918 calculated for different combinations of evaluatedness and :type t.
919 Regard the two first columns as input and the next two as output.
921 # | t | :type t | rtti(t) | improv. | result
922 ------------------------------------------------------------
923 1 | _ | t b | a | none | OK
924 2 | _ | MkT b | a | none | OK
925 3 | _ | t Int | a | none | OK
927 If t is not evaluated at *all*, we are safe.
929 4 | (_ : _) | t b | [a] | t = [] | UNSOUND
930 5 | (_ : _) | MkT b | MkT a | none | OK (compensating for the missing newtype)
931 6 | (_ : _) | t Int | [Int] | t = [] | UNSOUND
933 If a is a minimal whnf, we run into trouble. Note that
934 row 5 above does newtype enrichment on the ty_rtty parameter.
936 7 | (Just _:_)| t b |[Maybe a] | t = [], | UNSOUND
939 8 | (Just _:_)| MkT b | MkT a | none | OK
940 9 | (Just _:_)| t Int | FAIL | none | OK
942 And if t is any more evaluated than whnf, we are still in trouble.
943 Because constraints are solved in top-down order, when we reach the
944 Maybe subterm what we got is already unsound. This explains why the
945 row 9 fails to complete.
947 10 | (Just _:_)| t Int | [Maybe a] | FAIL | OK
948 11 | (Just 1:_)| t Int | [Maybe Int] | FAIL | OK
950 We can undo the failure in row 9 by leaving out the constraint
951 coming from the type signature of t (i.e., the 2nd column).
952 Note that this type information is still used
953 to calculate the improvement. But we fail
954 when trying to calculate the improvement, as there is no unifier for
955 t Int = [Maybe a] or t Int = [Maybe Int].
958 Another set of examples with t :: [MkT (Maybe Int)] \equiv [[Maybe (Maybe Int)]]
960 # | t | :type t | rtti(t) | improvement | result
961 ---------------------------------------------------------------------
962 1 |(Just _:_) | [t (Maybe a)] | [[Maybe b]] | t = [] |
963 | | | | b = Maybe a |
967 Consider a function obtainType that takes a value and a type and produces
968 the Term representation and a substitution (the improvement).
969 Assume an auxiliar rtti' function which does the actual job if recovering
970 the type, but which may produce a false type.
974 rtti' :: a -> IO Type -- Does not use the static type information
976 obtainType :: a -> Type -> IO (Maybe (Term, Improvement))
977 obtainType v old_ty = do
979 if monomorphic rtti_ty || (check rtti_ty old_ty)
982 where check rtti_ty old_ty = check1 rtti_ty &&
983 check2 rtti_ty old_ty
985 check1 :: Type -> Bool
986 check2 :: Type -> Type -> Bool
988 Now, if rtti' returns a monomorphic type, we are safe.
989 If that is not the case, then we consider two conditions.
992 1. To prevent the class of unsoundness displayed by
993 rows 4 and 7 in the example: no higher kind tyvars
1000 2. To prevent the class of unsoundness shown by row 6,
1001 the rtti type should be structurally more
1002 defined than the old type we are comparing it to.
1003 check2 :: NewType -> OldType -> Bool
1006 check2 [a] (t Int) = False
1007 check2 [a] (t a) = False -- By check1 we never reach this equation
1008 check2 [Int] a = True
1009 check2 [Int] (t Int) = True
1010 check2 [Maybe a] (t Int) = False
1011 check2 [Maybe Int] (t Int) = True
1012 check2 (Maybe [a]) (m [Int]) = False
1013 check2 (Maybe [Int]) (m [Int]) = True
1017 check1 :: Type -> Bool
1018 check1 ty | (tvs, _, _) <- tcSplitSigmaTy ty = not $ any isHigherKind (map tyVarKind tvs)
1020 isHigherKind = not . null . fst . splitKindFunTys
1022 check2 :: Type -> Type -> Bool
1023 check2 sigma_rtti_ty sigma_old_ty
1024 | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty
1026 _ | Just (_,olds) <- tcSplitTyConApp_maybe old_ty
1027 -> and$ zipWith check2 rttis olds
1028 _ | Just _ <- splitAppTy_maybe old_ty
1029 -> isMonomorphicOnNonPhantomArgs rtti_ty
1032 where (_, _ , rtti_ty) = tcSplitSigmaTy sigma_rtti_ty
1033 (_, _ , old_ty) = tcSplitSigmaTy sigma_old_ty
1036 -- Dealing with newtypes
1037 --------------------------
1039 congruenceNewtypes does a parallel fold over two Type values,
1040 compensating for missing newtypes on both sides.
1041 This is necessary because newtypes are not present
1042 in runtime, but sometimes there is evidence available.
1043 Evidence can come from DataCon signatures or
1044 from compile-time type inference.
1045 What we are doing here is an approximation
1046 of unification modulo a set of equations derived
1047 from newtype definitions. These equations should be the
1048 same as the equality coercions generated for newtypes
1049 in System Fc. The idea is to perform a sort of rewriting,
1050 taking those equations as rules, before launching unification.
1052 The caller must ensure the following.
1053 The 1st type (lhs) comes from the heap structure of ptrs,nptrs.
1054 The 2nd type (rhs) comes from a DataCon type signature.
1055 Rewriting (i.e. adding/removing a newtype wrapper) can happen
1056 in both types, but in the rhs it is restricted to the result type.
1058 Note that it is very tricky to make this 'rewriting'
1059 work with the unification implemented by TcM, where
1060 substitutions are operationally inlined. The order in which
1061 constraints are unified is vital as we cannot modify
1062 anything that has been touched by a previous unification step.
1063 Therefore, congruenceNewtypes is sound only if the types
1064 recovered by the RTTI mechanism are unified Top-Down.
1066 congruenceNewtypes :: TcType -> TcType -> TR (TcType,TcType)
1067 congruenceNewtypes lhs rhs = go lhs rhs >>= \rhs' -> return (lhs,rhs')
1070 -- TyVar lhs inductive case
1071 | Just tv <- getTyVar_maybe l
1072 = recoverTR (return r) $ do
1073 Indirect ty_v <- readMetaTyVar tv
1074 traceTR $ fsep [text "(congruence) Following indirect tyvar:",
1075 ppr tv, equals, ppr ty_v]
1077 -- FunTy inductive case
1078 | Just (l1,l2) <- splitFunTy_maybe l
1079 , Just (r1,r2) <- splitFunTy_maybe r
1080 = do r2' <- go l2 r2
1082 return (mkFunTy r1' r2')
1083 -- TyconApp Inductive case; this is the interesting bit.
1084 | Just (tycon_l, _) <- tcSplitTyConApp_maybe lhs
1085 , Just (tycon_r, _) <- tcSplitTyConApp_maybe rhs
1086 , tycon_l /= tycon_r
1089 | otherwise = return r
1091 where upgrade :: TyCon -> Type -> TR Type
1092 upgrade new_tycon ty
1093 | not (isNewTyCon new_tycon) = do
1094 traceTR (text "(Upgrade) Not matching newtype evidence: " <>
1095 ppr new_tycon <> text " for " <> ppr ty)
1098 traceTR (text "(Upgrade) upgraded " <> ppr ty <>
1099 text " in presence of newtype evidence " <> ppr new_tycon)
1100 vars <- mapM (newVar . tyVarKind) (tyConTyVars new_tycon)
1101 let ty' = mkTyConApp new_tycon vars
1102 liftTcM (boxyUnify ty (repType ty'))
1103 -- assumes that reptype doesn't ^^^^ touch tyconApp args
1107 zonkTerm :: Term -> TcM Term
1108 zonkTerm = foldTermM TermFoldM{
1109 fTermM = \ty dc v tt -> zonkTcType ty >>= \ty' ->
1110 return (Term ty' dc v tt)
1111 ,fSuspensionM = \ct ty v b -> zonkTcType ty >>= \ty ->
1112 return (Suspension ct ty v b)
1113 ,fNewtypeWrapM= \ty dc t -> zonkTcType ty >>= \ty' ->
1114 return$ NewtypeWrap ty' dc t
1115 ,fRefWrapM = \ty t ->
1116 return RefWrap `ap` zonkTcType ty `ap` return t
1117 ,fPrimM = (return.) . Prim
1120 --------------------------------------------------------------------------------
1121 -- Restore Class predicates out of a representation type
1122 dictsView :: Type -> Type
1123 -- dictsView ty = ty
1124 dictsView (FunTy (TyConApp tc_dict args) ty)
1125 | Just c <- tyConClass_maybe tc_dict
1126 = FunTy (PredTy (ClassP c args)) (dictsView ty)
1128 | Just (tc_fun, [TyConApp tc_dict args, ty2]) <- tcSplitTyConApp_maybe ty
1129 , Just c <- tyConClass_maybe tc_dict
1130 = mkTyConApp tc_fun [PredTy (ClassP c args), dictsView ty2]
1134 -- Use only for RTTI types
1135 isMonomorphic :: RttiType -> Bool
1136 isMonomorphic ty = noExistentials && noUniversals
1137 where (tvs, _, ty') = tcSplitSigmaTy ty
1138 noExistentials = isEmptyVarSet (tyVarsOfType ty')
1139 noUniversals = null tvs
1141 -- Use only for RTTI types
1142 isMonomorphicOnNonPhantomArgs :: RttiType -> Bool
1143 isMonomorphicOnNonPhantomArgs ty
1144 | Just (tc, all_args) <- tcSplitTyConApp_maybe (repType ty)
1145 , phantom_vars <- tyConPhantomTyVars tc
1146 , concrete_args <- [ arg | (tyv,arg) <- tyConTyVars tc `zip` all_args
1147 , tyv `notElem` phantom_vars]
1148 = all isMonomorphicOnNonPhantomArgs concrete_args
1149 | Just (ty1, ty2) <- splitFunTy_maybe ty
1150 = all isMonomorphicOnNonPhantomArgs [ty1,ty2]
1151 | otherwise = isMonomorphic ty
1153 tyConPhantomTyVars :: TyCon -> [TyVar]
1154 tyConPhantomTyVars tc
1156 , Just dcs <- tyConDataCons_maybe tc
1157 , dc_vars <- concatMap dataConUnivTyVars dcs
1158 = tyConTyVars tc \\ dc_vars
1159 tyConPhantomTyVars _ = []
1161 -- Is this defined elsewhere?
1162 -- Generalize the type: find all free tyvars and wrap in the appropiate ForAll.
1163 sigmaType :: Type -> Type
1164 sigmaType ty = mkSigmaTy (varSetElems$ tyVarsOfType ty) [] ty
1167 mapMif :: Monad m => (a -> Bool) -> (a -> m a) -> [a] -> m [a]
1168 mapMif pred f xx = sequence $ mapMif_ pred f xx
1171 mapMif_ pred f (x:xx) = (if pred x then f x else return x) : mapMif_ pred f xx
1173 unlessM :: Monad m => m Bool -> m () -> m ()
1174 unlessM condM acc = condM >>= \c -> unless c acc
1177 -- Strict application of f at index i
1178 appArr :: Ix i => (e -> a) -> Array i e -> Int -> a
1179 appArr f a@(Array _ _ _ ptrs#) i@(I# i#)
1180 = ASSERT2 (i < length(elems a), ppr(length$ elems a, i))
1181 case indexArray# ptrs# i# of
1184 amap' :: (t -> b) -> Array Int t -> [b]
1185 amap' f (Array i0 i _ arr#) = map g [0 .. i - i0]
1186 where g (I# i#) = case indexArray# arr# i# of
1190 isLifted :: Type -> Bool
1191 isLifted = not . isUnLiftedType
1193 extractUnboxed :: [Type] -> Closure -> [[Word]]
1194 extractUnboxed tt clos = go tt (nonPtrs clos)
1196 | Just (tycon,_) <- tcSplitTyConApp_maybe t
1197 = ASSERT (isPrimTyCon tycon) sizeofTyCon tycon
1198 | otherwise = pprPanic "Expected a TcTyCon" (ppr t)
1201 | (x, rest) <- splitAt (sizeofType t) xx
1204 sizeofTyCon :: TyCon -> Int -- in *words*
1205 sizeofTyCon = primRepSizeW . tyConPrimRep
1208 (|.|) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
1209 (f |.| g) x = f x || g x