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(..) )
63 import GHC.IOBase ( IO(IO) )
67 import Data.Array.Base
70 import qualified Data.Sequence as Seq
72 import Data.Sequence hiding (null, length, index, take, drop, splitAt, reverse)
74 import System.IO.Unsafe
77 ---------------------------------------------
78 -- * A representation of semi evaluated Terms
79 ---------------------------------------------
81 data Term = Term { ty :: RttiType
82 , dc :: Either String DataCon
83 -- Carries a text representation if the datacon is
84 -- not exported by the .hi file, which is the case
85 -- for private constructors in -O0 compiled libraries
87 , subTerms :: [Term] }
89 | Prim { ty :: RttiType
92 | Suspension { ctype :: ClosureType
95 , bound_to :: Maybe Name -- Useful for printing
97 | NewtypeWrap{ -- At runtime there are no newtypes, and hence no
98 -- newtype constructors. A NewtypeWrap is just a
99 -- made-up tag saying "heads up, there used to be
100 -- a newtype constructor here".
102 , dc :: Either String DataCon
103 , wrapped_term :: Term }
104 | RefWrap { -- The contents of a reference
106 , wrapped_term :: Term }
108 isTerm, isSuspension, isPrim, isFun, isFunLike, isNewtypeWrap :: Term -> Bool
111 isSuspension Suspension{} = True
112 isSuspension _ = False
115 isNewtypeWrap NewtypeWrap{} = True
116 isNewtypeWrap _ = False
118 isFun Suspension{ctype=Fun} = True
121 isFunLike s@Suspension{ty=ty} = isFun s || isFunTy ty
124 termType :: Term -> RttiType
127 isFullyEvaluatedTerm :: Term -> Bool
128 isFullyEvaluatedTerm Term {subTerms=tt} = all isFullyEvaluatedTerm tt
129 isFullyEvaluatedTerm Prim {} = True
130 isFullyEvaluatedTerm NewtypeWrap{wrapped_term=t} = isFullyEvaluatedTerm t
131 isFullyEvaluatedTerm RefWrap{wrapped_term=t} = isFullyEvaluatedTerm t
132 isFullyEvaluatedTerm _ = False
134 instance Outputable (Term) where
135 ppr t | Just doc <- cPprTerm cPprTermBase t = doc
136 | otherwise = panic "Outputable Term instance"
138 -------------------------------------------------------------------------
139 -- Runtime Closure Datatype and functions for retrieving closure related stuff
140 -------------------------------------------------------------------------
141 data ClosureType = Constr
154 data Closure = Closure { tipe :: ClosureType
156 , infoTable :: StgInfoTable
157 , ptrs :: Array Int HValue
161 instance Outputable ClosureType where
164 #include "../includes/ClosureTypes.h"
166 aP_CODE, pAP_CODE :: Int
172 getClosureData :: a -> IO Closure
174 case unpackClosure# a of
175 (# iptr, ptrs, nptrs #) -> do
177 | ghciTablesNextToCode =
180 -- the info pointer we get back from unpackClosure#
181 -- is to the beginning of the standard info table,
182 -- but the Storable instance for info tables takes
183 -- into account the extra entry pointer when
184 -- !ghciTablesNextToCode, so we must adjust here:
185 Ptr iptr `plusPtr` negate wORD_SIZE
187 let tipe = readCType (BCI.tipe itbl)
188 elems = fromIntegral (BCI.ptrs itbl)
189 ptrsList = Array 0 (elems - 1) elems ptrs
190 nptrs_data = [W# (indexWordArray# nptrs i)
191 | I# i <- [0.. fromIntegral (BCI.nptrs itbl)] ]
192 ASSERT(elems >= 0) return ()
194 return (Closure tipe (Ptr iptr) itbl ptrsList nptrs_data)
196 readCType :: Integral a => a -> ClosureType
198 | i >= CONSTR && i <= CONSTR_NOCAF_STATIC = Constr
199 | i >= FUN && i <= FUN_STATIC = Fun
200 | i >= THUNK && i < THUNK_SELECTOR = Thunk i'
201 | i == THUNK_SELECTOR = ThunkSelector
202 | i == BLACKHOLE = Blackhole
203 | i >= IND && i <= IND_STATIC = Indirection i'
206 | i' == pAP_CODE = PAP
207 | i == MUT_VAR_CLEAN || i == MUT_VAR_DIRTY= MutVar i'
208 | i == MVAR_CLEAN || i == MVAR_DIRTY = MVar i'
209 | otherwise = Other i'
210 where i' = fromIntegral i
212 isConstr, isIndirection, isThunk :: ClosureType -> Bool
213 isConstr Constr = True
216 isIndirection (Indirection _) = True
217 isIndirection _ = False
219 isThunk (Thunk _) = True
220 isThunk ThunkSelector = True
224 isFullyEvaluated :: a -> IO Bool
225 isFullyEvaluated a = do
226 closure <- getClosureData a
228 Constr -> do are_subs_evaluated <- amapM isFullyEvaluated (ptrs closure)
229 return$ and are_subs_evaluated
231 where amapM f = sequence . amap' f
233 -- TODO: Fix it. Probably the otherwise case is failing, trace/debug it
235 unsafeDeepSeq :: a -> b -> b
236 unsafeDeepSeq = unsafeDeepSeq1 2
237 where unsafeDeepSeq1 0 a b = seq a $! b
238 unsafeDeepSeq1 i a b -- 1st case avoids infinite loops for non reducible thunks
239 | not (isConstr tipe) = seq a $! unsafeDeepSeq1 (i-1) a b
240 -- | unsafePerformIO (isFullyEvaluated a) = b
241 | otherwise = case unsafePerformIO (getClosureData a) of
242 closure -> foldl' (flip unsafeDeepSeq) b (ptrs closure)
243 where tipe = unsafePerformIO (getClosureType a)
246 -----------------------------------
247 -- * Traversals for Terms
248 -----------------------------------
249 type TermProcessor a b = RttiType -> Either String DataCon -> HValue -> [a] -> b
251 data TermFold a = TermFold { fTerm :: TermProcessor a a
252 , fPrim :: RttiType -> [Word] -> a
253 , fSuspension :: ClosureType -> RttiType -> HValue
255 , fNewtypeWrap :: RttiType -> Either String DataCon
257 , fRefWrap :: RttiType -> a -> a
262 TermFoldM {fTermM :: TermProcessor a (m a)
263 , fPrimM :: RttiType -> [Word] -> m a
264 , fSuspensionM :: ClosureType -> RttiType -> HValue
266 , fNewtypeWrapM :: RttiType -> Either String DataCon
268 , fRefWrapM :: RttiType -> a -> m a
271 foldTerm :: TermFold a -> Term -> a
272 foldTerm tf (Term ty dc v tt) = fTerm tf ty dc v (map (foldTerm tf) tt)
273 foldTerm tf (Prim ty v ) = fPrim tf ty v
274 foldTerm tf (Suspension ct ty v b) = fSuspension tf ct ty v b
275 foldTerm tf (NewtypeWrap ty dc t) = fNewtypeWrap tf ty dc (foldTerm tf t)
276 foldTerm tf (RefWrap ty t) = fRefWrap tf ty (foldTerm tf t)
279 foldTermM :: Monad m => TermFoldM m a -> Term -> m a
280 foldTermM tf (Term ty dc v tt) = mapM (foldTermM tf) tt >>= fTermM tf ty dc v
281 foldTermM tf (Prim ty v ) = fPrimM tf ty v
282 foldTermM tf (Suspension ct ty v b) = fSuspensionM tf ct ty v b
283 foldTermM tf (NewtypeWrap ty dc t) = foldTermM tf t >>= fNewtypeWrapM tf ty dc
284 foldTermM tf (RefWrap ty t) = foldTermM tf t >>= fRefWrapM tf ty
286 idTermFold :: TermFold Term
287 idTermFold = TermFold {
290 fSuspension = Suspension,
291 fNewtypeWrap = NewtypeWrap,
295 mapTermType :: (RttiType -> Type) -> Term -> Term
296 mapTermType f = foldTerm idTermFold {
297 fTerm = \ty dc hval tt -> Term (f ty) dc hval tt,
298 fSuspension = \ct ty hval n ->
299 Suspension ct (f ty) hval n,
300 fNewtypeWrap= \ty dc t -> NewtypeWrap (f ty) dc t,
301 fRefWrap = \ty t -> RefWrap (f ty) t}
303 mapTermTypeM :: Monad m => (RttiType -> m Type) -> Term -> m Term
304 mapTermTypeM f = foldTermM TermFoldM {
305 fTermM = \ty dc hval tt -> f ty >>= \ty' -> return $ Term ty' dc hval tt,
306 fPrimM = (return.) . Prim,
307 fSuspensionM = \ct ty hval n ->
308 f ty >>= \ty' -> return $ Suspension ct ty' hval n,
309 fNewtypeWrapM= \ty dc t -> f ty >>= \ty' -> return $ NewtypeWrap ty' dc t,
310 fRefWrapM = \ty t -> f ty >>= \ty' -> return $ RefWrap ty' t}
312 termTyVars :: Term -> TyVarSet
313 termTyVars = foldTerm TermFold {
314 fTerm = \ty _ _ tt ->
315 tyVarsOfType ty `plusVarEnv` concatVarEnv tt,
316 fSuspension = \_ ty _ _ -> tyVarsOfType ty,
317 fPrim = \ _ _ -> emptyVarEnv,
318 fNewtypeWrap= \ty _ t -> tyVarsOfType ty `plusVarEnv` t,
319 fRefWrap = \ty t -> tyVarsOfType ty `plusVarEnv` t}
320 where concatVarEnv = foldr plusVarEnv emptyVarEnv
322 ----------------------------------
323 -- Pretty printing of terms
324 ----------------------------------
326 type Precedence = Int
327 type TermPrinter = Precedence -> Term -> SDoc
328 type TermPrinterM m = Precedence -> Term -> m SDoc
330 app_prec,cons_prec, max_prec ::Int
333 cons_prec = 5 -- TODO Extract this info from GHC itself
335 pprTerm :: TermPrinter -> TermPrinter
336 pprTerm y p t | Just doc <- pprTermM (\p -> Just . y p) p t = doc
337 pprTerm _ _ _ = panic "pprTerm"
339 pprTermM, ppr_termM, pprNewtypeWrap :: Monad m => TermPrinterM m -> TermPrinterM m
340 pprTermM y p t = pprDeeper `liftM` ppr_termM y p t
342 ppr_termM y p Term{dc=Left dc_tag, subTerms=tt} = do
343 tt_docs <- mapM (y app_prec) tt
344 return$ cparen (not(null tt) && p >= app_prec) (text dc_tag <+> pprDeeperList fsep tt_docs)
346 ppr_termM y p Term{dc=Right dc, subTerms=tt}
347 {- | dataConIsInfix dc, (t1:t2:tt') <- tt --TODO fixity
348 = parens (ppr_term1 True t1 <+> ppr dc <+> ppr_term1 True ppr t2)
349 <+> hsep (map (ppr_term1 True) tt)
350 -} -- TODO Printing infix constructors properly
351 | null tt = return$ ppr dc
353 tt_docs <- mapM (y app_prec) tt
354 return$ cparen (p >= app_prec) (ppr dc <+> pprDeeperList fsep tt_docs)
356 ppr_termM y p t@NewtypeWrap{} = pprNewtypeWrap y p t
357 ppr_termM y p RefWrap{wrapped_term=t} = do
358 contents <- y app_prec t
359 return$ cparen (p >= app_prec) (text "GHC.Prim.MutVar#" <+> contents)
360 -- The constructor name is wired in here ^^^ for the sake of simplicity.
361 -- I don't think mutvars are going to change in a near future.
362 -- In any case this is solely a presentation matter: MutVar# is
363 -- a datatype with no constructors, implemented by the RTS
364 -- (hence there is no way to obtain a datacon and print it).
365 ppr_termM _ _ t = ppr_termM1 t
368 ppr_termM1 :: Monad m => Term -> m SDoc
369 ppr_termM1 Prim{value=words, ty=ty} =
370 return$ text$ repPrim (tyConAppTyCon ty) words
371 ppr_termM1 Suspension{ty=ty, bound_to=Nothing} =
372 return (char '_' <+> ifPprDebug (text "::" <> ppr ty))
373 ppr_termM1 Suspension{ty=ty, bound_to=Just n}
374 -- | Just _ <- splitFunTy_maybe ty = return$ ptext (sLit("<function>")
375 | otherwise = return$ parens$ ppr n <> text "::" <> ppr ty
376 ppr_termM1 Term{} = panic "ppr_termM1 - Term"
377 ppr_termM1 RefWrap{} = panic "ppr_termM1 - RefWrap"
378 ppr_termM1 NewtypeWrap{} = panic "ppr_termM1 - NewtypeWrap"
380 pprNewtypeWrap y p NewtypeWrap{ty=ty, wrapped_term=t}
381 | Just (tc,_) <- tcSplitTyConApp_maybe ty
382 , ASSERT(isNewTyCon tc) True
383 , Just new_dc <- tyConSingleDataCon_maybe tc = do
384 real_term <- y max_prec t
385 return$ cparen (p >= app_prec) (ppr new_dc <+> real_term)
386 pprNewtypeWrap _ _ _ = panic "pprNewtypeWrap"
388 -------------------------------------------------------
389 -- Custom Term Pretty Printers
390 -------------------------------------------------------
392 -- We can want to customize the representation of a
393 -- term depending on its type.
394 -- However, note that custom printers have to work with
395 -- type representations, instead of directly with types.
396 -- We cannot use type classes here, unless we employ some
397 -- typerep trickery (e.g. Weirich's RepLib tricks),
398 -- which I didn't. Therefore, this code replicates a lot
399 -- of what type classes provide for free.
401 type CustomTermPrinter m = TermPrinterM m
402 -> [Precedence -> Term -> (m (Maybe SDoc))]
404 -- | Takes a list of custom printers with a explicit recursion knot and a term,
405 -- and returns the output of the first succesful printer, or the default printer
406 cPprTerm :: Monad m => CustomTermPrinter m -> Term -> m SDoc
407 cPprTerm printers_ = go 0 where
408 printers = printers_ go
410 let default_ = Just `liftM` pprTermM go prec t
411 mb_customDocs = [pp prec t | pp <- printers] ++ [default_]
412 Just doc <- firstJustM mb_customDocs
413 return$ cparen (prec>app_prec+1) doc
415 firstJustM (mb:mbs) = mb >>= maybe (firstJustM mbs) (return . Just)
416 firstJustM [] = return Nothing
418 -- Default set of custom printers. Note that the recursion knot is explicit
419 cPprTermBase :: Monad m => CustomTermPrinter m
421 [ ifTerm (isTupleTy.ty) (\_p -> liftM (parens . hcat . punctuate comma)
424 , ifTerm (\t -> isTyCon listTyCon (ty t) && subTerms t `lengthIs` 2)
425 (\ p Term{subTerms=[h,t]} -> doList p h t)
426 , ifTerm (isTyCon intTyCon . ty) (coerceShow$ \(a::Int)->a)
427 , ifTerm (isTyCon charTyCon . ty) (coerceShow$ \(a::Char)->a)
428 , ifTerm (isTyCon floatTyCon . ty) (coerceShow$ \(a::Float)->a)
429 , ifTerm (isTyCon doubleTyCon . ty) (coerceShow$ \(a::Double)->a)
430 , ifTerm (isIntegerTy . ty) (coerceShow$ \(a::Integer)->a)
432 where ifTerm pred f prec t@Term{}
433 | pred t = Just `liftM` f prec t
434 ifTerm _ _ _ _ = return Nothing
436 isIntegerTy ty = fromMaybe False $ do
437 (tc,_) <- tcSplitTyConApp_maybe ty
438 return (tyConName tc == integerTyConName)
440 isTupleTy ty = fromMaybe False $ do
441 (tc,_) <- tcSplitTyConApp_maybe ty
442 return (isBoxedTupleTyCon tc)
444 isTyCon a_tc ty = fromMaybe False $ do
445 (tc,_) <- tcSplitTyConApp_maybe ty
448 coerceShow f _p = return . text . show . f . unsafeCoerce# . val
450 --Note pprinting of list terms is not lazy
452 let elems = h : getListTerms t
453 isConsLast = not(termType(last elems) `coreEqType` termType h)
454 print_elems <- mapM (y cons_prec) elems
455 return$ if isConsLast
456 then cparen (p >= cons_prec)
458 . punctuate (space<>colon)
460 else brackets (pprDeeperList fcat$
461 punctuate comma print_elems)
463 where getListTerms Term{subTerms=[h,t]} = h : getListTerms t
464 getListTerms Term{subTerms=[]} = []
465 getListTerms t@Suspension{} = [t]
466 getListTerms t = pprPanic "getListTerms" (ppr t)
469 repPrim :: TyCon -> [Word] -> String
470 repPrim t = rep where
472 | t == charPrimTyCon = show (build x :: Char)
473 | t == intPrimTyCon = show (build x :: Int)
474 | t == wordPrimTyCon = show (build x :: Word)
475 | t == floatPrimTyCon = show (build x :: Float)
476 | t == doublePrimTyCon = show (build x :: Double)
477 | t == int32PrimTyCon = show (build x :: Int32)
478 | t == word32PrimTyCon = show (build x :: Word32)
479 | t == int64PrimTyCon = show (build x :: Int64)
480 | t == word64PrimTyCon = show (build x :: Word64)
481 | t == addrPrimTyCon = show (nullPtr `plusPtr` build x)
482 | t == stablePtrPrimTyCon = "<stablePtr>"
483 | t == stableNamePrimTyCon = "<stableName>"
484 | t == statePrimTyCon = "<statethread>"
485 | t == realWorldTyCon = "<realworld>"
486 | t == threadIdPrimTyCon = "<ThreadId>"
487 | t == weakPrimTyCon = "<Weak>"
488 | t == arrayPrimTyCon = "<array>"
489 | t == byteArrayPrimTyCon = "<bytearray>"
490 | t == mutableArrayPrimTyCon = "<mutableArray>"
491 | t == mutableByteArrayPrimTyCon = "<mutableByteArray>"
492 | t == mutVarPrimTyCon= "<mutVar>"
493 | t == mVarPrimTyCon = "<mVar>"
494 | t == tVarPrimTyCon = "<tVar>"
495 | otherwise = showSDoc (char '<' <> ppr t <> char '>')
496 where build ww = unsafePerformIO $ withArray ww (peek . castPtr)
497 -- This ^^^ relies on the representation of Haskell heap values being
498 -- the same as in a C array.
500 -----------------------------------
501 -- Type Reconstruction
502 -----------------------------------
504 Type Reconstruction is type inference done on heap closures.
505 The algorithm walks the heap generating a set of equations, which
506 are solved with syntactic unification.
507 A type reconstruction equation looks like:
509 <datacon reptype> = <actual heap contents>
511 The full equation set is generated by traversing all the subterms, starting
514 The only difficult part is that newtypes are only found in the lhs of equations.
515 Right hand sides are missing them. We can either (a) drop them from the lhs, or
516 (b) reconstruct them in the rhs when possible.
518 The function congruenceNewtypes takes a shot at (b)
522 -- A (non-mutable) tau type containing
523 -- existentially quantified tyvars.
524 -- (since GHC type language currently does not support
525 -- existentials, we leave these variables unquantified)
528 -- An incomplete type as stored in GHCi:
529 -- no polymorphism: no quantifiers & all tyvars are skolem.
533 -- The Type Reconstruction monad
534 --------------------------------
537 runTR :: HscEnv -> TR a -> IO a
538 runTR hsc_env thing = do
539 mb_val <- runTR_maybe hsc_env thing
541 Nothing -> error "unable to :print the term"
544 runTR_maybe :: HscEnv -> TR a -> IO (Maybe a)
545 runTR_maybe hsc_env = fmap snd . initTc hsc_env HsSrcFile False iNTERACTIVE
547 traceTR :: SDoc -> TR ()
548 traceTR = liftTcM . traceOptTcRn Opt_D_dump_rtti
551 -- Semantically different to recoverM in TcRnMonad
552 -- recoverM retains the errors in the first action,
553 -- whereas recoverTc here does not
554 recoverTR :: TR a -> TR a -> TR a
555 recoverTR recover thing = do
556 (_,mb_res) <- tryTcErrs thing
559 Just res -> return res
562 trIO = liftTcM . liftIO
564 liftTcM :: TcM a -> TR a
567 newVar :: Kind -> TR TcType
568 newVar = liftTcM . liftM mkTyVarTy . newBoxyTyVar
570 -- | Returns the instantiated type scheme ty', and the substitution sigma
571 -- such that sigma(ty') = ty
572 instScheme :: Type -> TR (TcType, TvSubst)
573 instScheme ty = liftTcM$ do
574 (tvs, _, _) <- tcInstType return ty
575 (tvs',_,ty') <- tcInstType (mapM tcInstTyVar) ty
576 return (ty', zipTopTvSubst tvs' (mkTyVarTys tvs))
578 -- Adds a constraint of the form t1 == t2
579 -- t1 is expected to come from walking the heap
580 -- t2 is expected to come from a datacon signature
581 -- Before unification, congruenceNewtypes needs to
583 addConstraint :: TcType -> TcType -> TR ()
584 addConstraint actual expected = do
585 traceTR (text "add constraint:" <+> fsep [ppr actual, equals, ppr expected])
586 recoverTR (traceTR $ fsep [text "Failed to unify", ppr actual,
587 text "with", ppr expected])
588 (congruenceNewtypes actual expected >>=
589 (getLIE . uncurry boxyUnify) >> return ())
590 -- TOMDO: what about the coercion?
591 -- we should consider family instances
594 -- Type & Term reconstruction
595 ------------------------------
596 cvObtainTerm :: HscEnv -> Int -> Bool -> RttiType -> HValue -> IO Term
597 cvObtainTerm hsc_env max_depth force old_ty hval = runTR hsc_env $ do
598 -- we quantify existential tyvars as universal,
599 -- as this is needed to be able to manipulate
601 let sigma_old_ty = sigmaType old_ty
602 traceTR (text "Term reconstruction started with initial type " <> ppr old_ty)
604 if isMonomorphic sigma_old_ty
606 new_ty <- go max_depth sigma_old_ty sigma_old_ty hval >>= zonkTerm
607 return $ fixFunDictionaries $ expandNewtypes new_ty
609 (old_ty', rev_subst) <- instScheme sigma_old_ty
610 my_ty <- newVar argTypeKind
611 when (check1 sigma_old_ty) (traceTR (text "check1 passed") >>
612 addConstraint my_ty old_ty')
613 term <- go max_depth my_ty sigma_old_ty hval
614 zterm <- zonkTerm term
615 let new_ty = termType zterm
616 if isMonomorphic new_ty || check2 (sigmaType new_ty) sigma_old_ty
618 traceTR (text "check2 passed")
619 addConstraint (termType term) old_ty'
620 zterm' <- zonkTerm term
621 return ((fixFunDictionaries . expandNewtypes . mapTermType (substTy rev_subst)) zterm')
623 traceTR (text "check2 failed" <+> parens
624 (ppr zterm <+> text "::" <+> ppr new_ty))
625 -- we have unsound types. Replace constructor types in
626 -- subterms with tyvars
627 zterm' <- mapTermTypeM
628 (\ty -> case tcSplitTyConApp_maybe ty of
629 Just (tc, _:_) | tc /= funTyCon
630 -> newVar argTypeKind
634 traceTR (text "Term reconstruction completed." $$
635 text "Term obtained: " <> ppr term $$
636 text "Type obtained: " <> ppr (termType term))
639 go :: Int -> Type -> Type -> HValue -> TcM Term
640 go max_depth _ _ _ | seq max_depth False = undefined
641 go 0 my_ty _old_ty a = do
642 traceTR (text "Gave up reconstructing a term after" <>
643 int max_depth <> text " steps")
644 clos <- trIO $ getClosureData a
645 return (Suspension (tipe clos) my_ty a Nothing)
646 go max_depth my_ty old_ty a = do
647 let monomorphic = not(isTyVarTy my_ty)
648 -- This ^^^ is a convention. The ancestor tests for
649 -- monomorphism and passes a type instead of a tv
650 clos <- trIO $ getClosureData a
652 -- Thunks we may want to force
653 -- NB. this won't attempt to force a BLACKHOLE. Even with :force, we never
654 -- force blackholes, because it would almost certainly result in deadlock,
655 -- and showing the '_' is more useful.
656 t | isThunk t && force -> traceTR (text "Forcing a " <> text (show t)) >>
657 seq a (go (pred max_depth) my_ty old_ty a)
658 -- We always follow indirections
659 Indirection i -> do traceTR (text "Following an indirection" <> parens (int i) )
660 go max_depth my_ty old_ty $! (ptrs clos ! 0)
661 -- We also follow references
662 MutVar _ | Just (tycon,[world,contents_ty]) <- tcSplitTyConApp_maybe old_ty
664 -- Deal with the MutVar# primitive
665 -- It does not have a constructor at all,
666 -- so we simulate the following one
667 -- MutVar# :: contents_ty -> MutVar# s contents_ty
668 traceTR (text "Following a MutVar")
669 contents_tv <- newVar liftedTypeKind
670 contents <- trIO$ IO$ \w -> readMutVar# (unsafeCoerce# a) w
671 ASSERT(isUnliftedTypeKind $ typeKind my_ty) return ()
672 (mutvar_ty,_) <- instScheme $ sigmaType $ mkFunTy
673 contents_ty (mkTyConApp tycon [world,contents_ty])
674 addConstraint (mkFunTy contents_tv my_ty) mutvar_ty
675 x <- go (pred max_depth) contents_tv contents_ty contents
676 return (RefWrap my_ty x)
678 -- The interesting case
680 traceTR (text "entering a constructor " <>
682 then parens (text "already monomorphic: " <> ppr my_ty)
683 else Outputable.empty)
684 Right dcname <- dataConInfoPtrToName (infoPtr clos)
685 (_,mb_dc) <- tryTcErrs (tcLookupDataCon dcname)
687 Nothing -> do -- This can happen for private constructors compiled -O0
688 -- where the .hi descriptor does not export them
689 -- In such case, we return a best approximation:
690 -- ignore the unpointed args, and recover the pointeds
691 -- This preserves laziness, and should be safe.
692 let tag = showSDoc (ppr dcname)
693 vars <- replicateM (length$ elems$ ptrs clos)
694 (newVar (liftedTypeKind))
695 subTerms <- sequence [appArr (go (pred max_depth) tv tv) (ptrs clos) i
696 | (i, tv) <- zip [0..] vars]
697 return (Term my_ty (Left ('<' : tag ++ ">")) a subTerms)
699 let subTtypes = matchSubTypes dc old_ty
700 subTermTvs <- mapMif (not . isMonomorphic)
701 (\t -> newVar (typeKind t))
703 let (subTermsP, subTermsNP) = partition (\(ty,_) -> isLifted ty
705 (zip subTtypes subTermTvs)
706 (subTtypesP, subTermTvsP ) = unzip subTermsP
707 (subTtypesNP, _subTermTvsNP) = unzip subTermsNP
709 -- When we already have all the information, avoid solving
710 -- unnecessary constraints. Propagation of type information
711 -- to subterms is already being done via matching.
712 when (not monomorphic) $ do
713 let myType = mkFunTys subTermTvs my_ty
714 (signatureType,_) <- instScheme (mydataConType dc)
715 -- It is vital for newtype reconstruction that the unification step
716 -- is done right here, _before_ the subterms are RTTI reconstructed
717 addConstraint myType signatureType
718 subTermsP <- sequence
719 [ appArr (go (pred max_depth) tv t) (ptrs clos) i
720 | (i,tv,t) <- zip3 [0..] subTermTvsP subTtypesP]
721 let unboxeds = extractUnboxed subTtypesNP clos
722 subTermsNP = map (uncurry Prim) (zip subTtypesNP unboxeds)
723 subTerms = reOrderTerms subTermsP subTermsNP subTtypes
724 return (Term my_ty (Right dc) a subTerms)
725 -- The otherwise case: can be a Thunk,AP,PAP,etc.
727 return (Suspension tipe_clos my_ty a Nothing)
730 | ty' <- repType ty -- look through newtypes
731 , Just (tc,ty_args) <- tcSplitTyConApp_maybe ty'
732 , dc `elem` tyConDataCons tc
733 -- It is necessary to check that dc is actually a constructor for tycon tc,
734 -- because it may be the case that tc is a recursive newtype and tcSplitTyConApp
735 -- has not removed it. In that case, we happily give up and don't match
736 = myDataConInstArgTys dc ty_args
737 | otherwise = dataConRepArgTys dc
739 -- put together pointed and nonpointed subterms in the
741 reOrderTerms _ _ [] = []
742 reOrderTerms pointed unpointed (ty:tys)
743 | isLifted ty || isRefType ty
744 = ASSERT2(not(null pointed)
745 , ptext (sLit "reOrderTerms") $$
746 (ppr pointed $$ ppr unpointed))
747 let (t:tt) = pointed in t : reOrderTerms tt unpointed tys
748 | otherwise = ASSERT2(not(null unpointed)
749 , ptext (sLit "reOrderTerms") $$
750 (ppr pointed $$ ppr unpointed))
751 let (t:tt) = unpointed in t : reOrderTerms pointed tt tys
753 -- insert NewtypeWraps around newtypes
754 expandNewtypes = foldTerm idTermFold { fTerm = worker } where
756 | Just (tc, args) <- tcSplitTyConApp_maybe ty
758 , wrapped_type <- newTyConInstRhs tc args
759 , Just dc' <- tyConSingleDataCon_maybe tc
760 , t' <- worker wrapped_type dc hval tt
761 = NewtypeWrap ty (Right dc') t'
762 | otherwise = Term ty dc hval tt
765 -- Avoid returning types where predicates have been expanded to dictionaries.
766 fixFunDictionaries = foldTerm idTermFold {fSuspension = worker} where
767 worker ct ty hval n | isFunTy ty = Suspension ct (dictsView ty) hval n
768 | otherwise = Suspension ct ty hval n
771 -- Fast, breadth-first Type reconstruction
772 ------------------------------------------
773 cvReconstructType :: HscEnv -> Int -> GhciType -> HValue -> IO (Maybe Type)
774 cvReconstructType hsc_env max_depth old_ty hval = runTR_maybe hsc_env $ do
775 traceTR (text "RTTI started with initial type " <> ppr old_ty)
776 let sigma_old_ty = sigmaType old_ty
778 if isMonomorphic sigma_old_ty
781 (old_ty', rev_subst) <- instScheme sigma_old_ty
782 my_ty <- newVar argTypeKind
783 when (check1 sigma_old_ty) (traceTR (text "check1 passed") >>
784 addConstraint my_ty old_ty')
785 search (isMonomorphic `fmap` zonkTcType my_ty)
787 (Seq.singleton (my_ty, hval))
789 new_ty <- zonkTcType my_ty
790 if isMonomorphic new_ty || check2 (sigmaType new_ty) sigma_old_ty
792 traceTR (text "check2 passed")
793 addConstraint my_ty old_ty'
794 new_ty' <- zonkTcType my_ty
795 return (substTy rev_subst new_ty')
796 else traceTR (text "check2 failed" <+> parens (ppr new_ty)) >>
798 traceTR (text "RTTI completed. Type obtained:" <+> ppr new_ty)
801 -- search :: m Bool -> ([a] -> [a] -> [a]) -> [a] -> m ()
802 search _ _ _ 0 = traceTR (text "Failed to reconstruct a type after " <>
803 int max_depth <> text " steps")
804 search stop expand l d =
807 x :< xx -> unlessM stop $ do
809 search stop expand (xx `mappend` Seq.fromList new) $! (pred d)
811 -- returns unification tasks,since we are going to want a breadth-first search
812 go :: Type -> HValue -> TR [(Type, HValue)]
814 clos <- trIO $ getClosureData a
816 Indirection _ -> go my_ty $! (ptrs clos ! 0)
818 contents <- trIO$ IO$ \w -> readMutVar# (unsafeCoerce# a) w
819 tv' <- newVar liftedTypeKind
820 world <- newVar liftedTypeKind
821 addConstraint my_ty (mkTyConApp mutVarPrimTyCon [world,tv'])
822 return [(tv', contents)]
824 Right dcname <- dataConInfoPtrToName (infoPtr clos)
825 (_,mb_dc) <- tryTcErrs (tcLookupDataCon dcname)
828 -- TODO: Check this case
829 forM [0..length (elems $ ptrs clos)] $ \i -> do
830 tv <- newVar liftedTypeKind
831 return$ appArr (\e->(tv,e)) (ptrs clos) i
834 subTtypes <- mapMif (not . isMonomorphic)
835 (\t -> newVar (typeKind t))
836 (dataConRepArgTys dc)
838 -- It is vital for newtype reconstruction that the unification step
839 -- is done right here, _before_ the subterms are RTTI reconstructed
840 let myType = mkFunTys subTtypes my_ty
841 (signatureType,_) <- instScheme(mydataConType dc)
842 addConstraint myType signatureType
843 return $ [ appArr (\e->(t,e)) (ptrs clos) i
844 | (i,t) <- zip [0..] (filter (isLifted |.| isRefType) subTtypes)]
847 -- Compute the difference between a base type and the type found by RTTI
848 -- improveType <base_type> <rtti_type>
849 -- The types can contain skolem type variables, which need to be treated as normal vars.
850 -- In particular, we want them to unify with things.
851 improveRTTIType :: HscEnv -> RttiType -> RttiType -> IO (Maybe TvSubst)
852 improveRTTIType hsc_env _ty rtti_ty = runTR_maybe hsc_env $ do
853 traceTR (text "improveRttiType" <+> fsep [ppr _ty, ppr rtti_ty])
854 (ty_tvs, _, _) <- tcInstType return ty
855 (ty_tvs', _, ty') <- tcInstType (mapM tcInstTyVar) ty
856 (_, _, rtti_ty') <- tcInstType (mapM tcInstTyVar) (sigmaType rtti_ty)
857 getLIE(boxyUnify rtti_ty' ty')
858 tvs1_contents <- zonkTcTyVars ty_tvs'
859 let subst = (uncurry zipTopTvSubst . unzip)
860 [(tv,ty) | (tv,ty) <- zip ty_tvs tvs1_contents
861 , getTyVar_maybe ty /= Just tv
862 --, not(isTyVarTy ty)
865 where ty = sigmaType _ty
867 myDataConInstArgTys :: DataCon -> [Type] -> [Type]
868 myDataConInstArgTys dc args
869 | null (dataConExTyVars dc) && null (dataConEqTheta dc) = dataConInstArgTys dc args
870 | otherwise = dataConRepArgTys dc
872 mydataConType :: DataCon -> Type
873 -- ^ Custom version of DataCon.dataConUserType where we
874 -- - remove the equality constraints
875 -- - use the representation types for arguments, including dictionaries
876 -- - keep the original result type
878 = mkForAllTys ((univ_tvs `minusList` map fst eq_spec) ++ ex_tvs) $
881 where univ_tvs = dataConUnivTyVars dc
882 ex_tvs = dataConExTyVars dc
883 eq_spec = dataConEqSpec dc
885 PredTy p -> predTypeRep p
887 | a <- dataConRepArgTys dc]
888 res_ty = dataConOrigResTy dc
890 isRefType :: Type -> Bool
892 | Just (tc, _) <- tcSplitTyConApp_maybe ty' = isRefTyCon tc
894 where ty'= repType ty
896 isRefTyCon :: TyCon -> Bool
897 isRefTyCon tc = tc `elem` [mutVarPrimTyCon, mVarPrimTyCon, tVarPrimTyCon]
902 This is not formalized anywhere, so hold to your seats!
903 RTTI in the presence of newtypes can be a tricky and unsound business.
907 Suppose we are doing RTTI for a partially evaluated
908 closure t, the real type of which is t :: MkT Int, for
910 newtype MkT a = MkT [Maybe a]
912 The table below shows the results of RTTI and the improvement
913 calculated for different combinations of evaluatedness and :type t.
914 Regard the two first columns as input and the next two as output.
916 # | t | :type t | rtti(t) | improv. | result
917 ------------------------------------------------------------
918 1 | _ | t b | a | none | OK
919 2 | _ | MkT b | a | none | OK
920 3 | _ | t Int | a | none | OK
922 If t is not evaluated at *all*, we are safe.
924 4 | (_ : _) | t b | [a] | t = [] | UNSOUND
925 5 | (_ : _) | MkT b | MkT a | none | OK (compensating for the missing newtype)
926 6 | (_ : _) | t Int | [Int] | t = [] | UNSOUND
928 If a is a minimal whnf, we run into trouble. Note that
929 row 5 above does newtype enrichment on the ty_rtty parameter.
931 7 | (Just _:_)| t b |[Maybe a] | t = [], | UNSOUND
934 8 | (Just _:_)| MkT b | MkT a | none | OK
935 9 | (Just _:_)| t Int | FAIL | none | OK
937 And if t is any more evaluated than whnf, we are still in trouble.
938 Because constraints are solved in top-down order, when we reach the
939 Maybe subterm what we got is already unsound. This explains why the
940 row 9 fails to complete.
942 10 | (Just _:_)| t Int | [Maybe a] | FAIL | OK
943 11 | (Just 1:_)| t Int | [Maybe Int] | FAIL | OK
945 We can undo the failure in row 9 by leaving out the constraint
946 coming from the type signature of t (i.e., the 2nd column).
947 Note that this type information is still used
948 to calculate the improvement. But we fail
949 when trying to calculate the improvement, as there is no unifier for
950 t Int = [Maybe a] or t Int = [Maybe Int].
953 Another set of examples with t :: [MkT (Maybe Int)] \equiv [[Maybe (Maybe Int)]]
955 # | t | :type t | rtti(t) | improvement | result
956 ---------------------------------------------------------------------
957 1 |(Just _:_) | [t (Maybe a)] | [[Maybe b]] | t = [] |
958 | | | | b = Maybe a |
962 Consider a function obtainType that takes a value and a type and produces
963 the Term representation and a substitution (the improvement).
964 Assume an auxiliar rtti' function which does the actual job if recovering
965 the type, but which may produce a false type.
969 rtti' :: a -> IO Type -- Does not use the static type information
971 obtainType :: a -> Type -> IO (Maybe (Term, Improvement))
972 obtainType v old_ty = do
974 if monomorphic rtti_ty || (check rtti_ty old_ty)
977 where check rtti_ty old_ty = check1 rtti_ty &&
978 check2 rtti_ty old_ty
980 check1 :: Type -> Bool
981 check2 :: Type -> Type -> Bool
983 Now, if rtti' returns a monomorphic type, we are safe.
984 If that is not the case, then we consider two conditions.
987 1. To prevent the class of unsoundness displayed by
988 rows 4 and 7 in the example: no higher kind tyvars
995 2. To prevent the class of unsoundness shown by row 6,
996 the rtti type should be structurally more
997 defined than the old type we are comparing it to.
998 check2 :: NewType -> OldType -> Bool
1001 check2 [a] (t Int) = False
1002 check2 [a] (t a) = False -- By check1 we never reach this equation
1003 check2 [Int] a = True
1004 check2 [Int] (t Int) = True
1005 check2 [Maybe a] (t Int) = False
1006 check2 [Maybe Int] (t Int) = True
1007 check2 (Maybe [a]) (m [Int]) = False
1008 check2 (Maybe [Int]) (m [Int]) = True
1012 check1 :: Type -> Bool
1013 check1 ty | (tvs, _, _) <- tcSplitSigmaTy ty = not $ any isHigherKind (map tyVarKind tvs)
1015 isHigherKind = not . null . fst . splitKindFunTys
1017 check2 :: Type -> Type -> Bool
1018 check2 sigma_rtti_ty sigma_old_ty
1019 | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty
1021 _ | Just (_,olds) <- tcSplitTyConApp_maybe old_ty
1022 -> and$ zipWith check2 rttis olds
1023 _ | Just _ <- splitAppTy_maybe old_ty
1024 -> isMonomorphicOnNonPhantomArgs rtti_ty
1027 where (_, _ , rtti_ty) = tcSplitSigmaTy sigma_rtti_ty
1028 (_, _ , old_ty) = tcSplitSigmaTy sigma_old_ty
1031 -- Dealing with newtypes
1032 --------------------------
1034 congruenceNewtypes does a parallel fold over two Type values,
1035 compensating for missing newtypes on both sides.
1036 This is necessary because newtypes are not present
1037 in runtime, but sometimes there is evidence available.
1038 Evidence can come from DataCon signatures or
1039 from compile-time type inference.
1040 What we are doing here is an approximation
1041 of unification modulo a set of equations derived
1042 from newtype definitions. These equations should be the
1043 same as the equality coercions generated for newtypes
1044 in System Fc. The idea is to perform a sort of rewriting,
1045 taking those equations as rules, before launching unification.
1047 The caller must ensure the following.
1048 The 1st type (lhs) comes from the heap structure of ptrs,nptrs.
1049 The 2nd type (rhs) comes from a DataCon type signature.
1050 Rewriting (i.e. adding/removing a newtype wrapper) can happen
1051 in both types, but in the rhs it is restricted to the result type.
1053 Note that it is very tricky to make this 'rewriting'
1054 work with the unification implemented by TcM, where
1055 substitutions are operationally inlined. The order in which
1056 constraints are unified is vital as we cannot modify
1057 anything that has been touched by a previous unification step.
1058 Therefore, congruenceNewtypes is sound only if the types
1059 recovered by the RTTI mechanism are unified Top-Down.
1061 congruenceNewtypes :: TcType -> TcType -> TR (TcType,TcType)
1062 congruenceNewtypes lhs rhs = go lhs rhs >>= \rhs' -> return (lhs,rhs')
1065 -- TyVar lhs inductive case
1066 | Just tv <- getTyVar_maybe l
1067 = recoverTR (return r) $ do
1068 Indirect ty_v <- readMetaTyVar tv
1069 traceTR $ fsep [text "(congruence) Following indirect tyvar:",
1070 ppr tv, equals, ppr ty_v]
1072 -- FunTy inductive case
1073 | Just (l1,l2) <- splitFunTy_maybe l
1074 , Just (r1,r2) <- splitFunTy_maybe r
1075 = do r2' <- go l2 r2
1077 return (mkFunTy r1' r2')
1078 -- TyconApp Inductive case; this is the interesting bit.
1079 | Just (tycon_l, _) <- tcSplitTyConApp_maybe lhs
1080 , Just (tycon_r, _) <- tcSplitTyConApp_maybe rhs
1081 , tycon_l /= tycon_r
1084 | otherwise = return r
1086 where upgrade :: TyCon -> Type -> TR Type
1087 upgrade new_tycon ty
1088 | not (isNewTyCon new_tycon) = do
1089 traceTR (text "(Upgrade) Not matching newtype evidence: " <>
1090 ppr new_tycon <> text " for " <> ppr ty)
1093 traceTR (text "(Upgrade) upgraded " <> ppr ty <>
1094 text " in presence of newtype evidence " <> ppr new_tycon)
1095 vars <- mapM (newVar . tyVarKind) (tyConTyVars new_tycon)
1096 let ty' = mkTyConApp new_tycon vars
1097 liftTcM (boxyUnify ty (repType ty'))
1098 -- assumes that reptype doesn't ^^^^ touch tyconApp args
1102 zonkTerm :: Term -> TcM Term
1103 zonkTerm = foldTermM TermFoldM{
1104 fTermM = \ty dc v tt -> zonkTcType ty >>= \ty' ->
1105 return (Term ty' dc v tt)
1106 ,fSuspensionM = \ct ty v b -> zonkTcType ty >>= \ty ->
1107 return (Suspension ct ty v b)
1108 ,fNewtypeWrapM= \ty dc t -> zonkTcType ty >>= \ty' ->
1109 return$ NewtypeWrap ty' dc t
1110 ,fRefWrapM = \ty t ->
1111 return RefWrap `ap` zonkTcType ty `ap` return t
1112 ,fPrimM = (return.) . Prim
1115 --------------------------------------------------------------------------------
1116 -- Restore Class predicates out of a representation type
1117 dictsView :: Type -> Type
1118 -- dictsView ty = ty
1119 dictsView (FunTy (TyConApp tc_dict args) ty)
1120 | Just c <- tyConClass_maybe tc_dict
1121 = FunTy (PredTy (ClassP c args)) (dictsView ty)
1123 | Just (tc_fun, [TyConApp tc_dict args, ty2]) <- tcSplitTyConApp_maybe ty
1124 , Just c <- tyConClass_maybe tc_dict
1125 = mkTyConApp tc_fun [PredTy (ClassP c args), dictsView ty2]
1129 -- Use only for RTTI types
1130 isMonomorphic :: RttiType -> Bool
1131 isMonomorphic ty = noExistentials && noUniversals
1132 where (tvs, _, ty') = tcSplitSigmaTy ty
1133 noExistentials = isEmptyVarSet (tyVarsOfType ty')
1134 noUniversals = null tvs
1136 -- Use only for RTTI types
1137 isMonomorphicOnNonPhantomArgs :: RttiType -> Bool
1138 isMonomorphicOnNonPhantomArgs ty
1139 | Just (tc, all_args) <- tcSplitTyConApp_maybe (repType ty)
1140 , phantom_vars <- tyConPhantomTyVars tc
1141 , concrete_args <- [ arg | (tyv,arg) <- tyConTyVars tc `zip` all_args
1142 , tyv `notElem` phantom_vars]
1143 = all isMonomorphicOnNonPhantomArgs concrete_args
1144 | Just (ty1, ty2) <- splitFunTy_maybe ty
1145 = all isMonomorphicOnNonPhantomArgs [ty1,ty2]
1146 | otherwise = isMonomorphic ty
1148 tyConPhantomTyVars :: TyCon -> [TyVar]
1149 tyConPhantomTyVars tc
1151 , Just dcs <- tyConDataCons_maybe tc
1152 , dc_vars <- concatMap dataConUnivTyVars dcs
1153 = tyConTyVars tc \\ dc_vars
1154 tyConPhantomTyVars _ = []
1156 -- Is this defined elsewhere?
1157 -- Generalize the type: find all free tyvars and wrap in the appropiate ForAll.
1158 sigmaType :: Type -> Type
1159 sigmaType ty = mkSigmaTy (varSetElems$ tyVarsOfType ty) [] ty
1162 mapMif :: Monad m => (a -> Bool) -> (a -> m a) -> [a] -> m [a]
1163 mapMif pred f xx = sequence $ mapMif_ pred f xx
1166 mapMif_ pred f (x:xx) = (if pred x then f x else return x) : mapMif_ pred f xx
1168 unlessM :: Monad m => m Bool -> m () -> m ()
1169 unlessM condM acc = condM >>= \c -> unless c acc
1172 -- Strict application of f at index i
1173 appArr :: Ix i => (e -> a) -> Array i e -> Int -> a
1174 appArr f a@(Array _ _ _ ptrs#) i@(I# i#)
1175 = ASSERT2 (i < length(elems a), ppr(length$ elems a, i))
1176 case indexArray# ptrs# i# of
1179 amap' :: (t -> b) -> Array Int t -> [b]
1180 amap' f (Array i0 i _ arr#) = map g [0 .. i - i0]
1181 where g (I# i#) = case indexArray# arr# i# of
1185 isLifted :: Type -> Bool
1186 isLifted = not . isUnLiftedType
1188 extractUnboxed :: [Type] -> Closure -> [[Word]]
1189 extractUnboxed tt clos = go tt (nonPtrs clos)
1191 | Just (tycon,_) <- tcSplitTyConApp_maybe t
1192 = ASSERT (isPrimTyCon tycon) sizeofTyCon tycon
1193 | otherwise = pprPanic "Expected a TcTyCon" (ppr t)
1196 | (x, rest) <- splitAt (sizeofType t) xx
1199 sizeofTyCon :: TyCon -> Int -- in *words*
1200 sizeofTyCon = primRepSizeW . tyConPrimRep
1203 (|.|) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
1204 (f |.| g) x = f x || g x