1 -----------------------------------------------------------------------------
3 -- GHC Interactive support for inspecting arbitrary closures at runtime
5 -- Pepe Iborra (supported by Google SoC) 2006
7 -----------------------------------------------------------------------------
9 module RtClosureInspect(
11 cvObtainTerm, -- :: HscEnv -> Int -> Bool -> Maybe Type -> HValue -> IO Term
42 #include "HsVersions.h"
44 import ByteCodeItbls ( StgInfoTable )
45 import qualified ByteCodeItbls as BCI( StgInfoTable(..) )
46 import HscTypes ( HscEnv )
52 import TcRnMonad ( TcM, initTc, ioToTcRn,
75 import GHC.Arr ( Array(..) )
80 import Data.Array.Base
82 import Data.List ( partition )
83 import qualified Data.Sequence as Seq
85 import Data.Sequence hiding (null, length, index, take, drop, splitAt, reverse)
87 import System.IO.Unsafe
89 ---------------------------------------------
90 -- * A representation of semi evaluated Terms
91 ---------------------------------------------
93 A few examples in this representation:
95 > Just 10 = Term Data.Maybe Data.Maybe.Just (Just 10) [Term Int I# (10) "10"]
97 > (('a',_,_),_,('b',_,_)) =
98 Term ((Char,b,c),d,(Char,e,f)) (,,) (('a',_,_),_,('b',_,_))
99 [ Term (Char, b, c) (,,) ('a',_,_) [Term Char C# "a", Suspension, Suspension]
101 , Term (Char, e, f) (,,) ('b',_,_) [Term Char C# "b", Suspension, Suspension]]
104 data Term = Term { ty :: Type
105 , dc :: Either String DataCon
106 -- Empty if the datacon aint exported by the .hi
107 -- (private constructors in -O0 libraries)
109 , subTerms :: [Term] }
114 | Suspension { ctype :: ClosureType
115 , mb_ty :: Maybe Type
117 , bound_to :: Maybe Name -- Useful for printing
119 | NewtypeWrap{ ty :: Type
120 , dc :: Either String DataCon
121 , wrapped_term :: Term }
123 isTerm, isSuspension, isPrim, isNewtypeWrap :: Term -> Bool
126 isSuspension Suspension{} = True
127 isSuspension _ = False
130 isNewtypeWrap NewtypeWrap{} = True
131 isNewtypeWrap _ = False
133 termType :: Term -> Maybe Type
134 termType t@(Suspension {}) = mb_ty t
135 termType t = Just$ ty t
137 isFullyEvaluatedTerm :: Term -> Bool
138 isFullyEvaluatedTerm Term {subTerms=tt} = all isFullyEvaluatedTerm tt
139 isFullyEvaluatedTerm Prim {} = True
140 isFullyEvaluatedTerm NewtypeWrap{wrapped_term=t} = isFullyEvaluatedTerm t
141 isFullyEvaluatedTerm _ = False
143 instance Outputable (Term) where
144 ppr t | Just doc <- cPprTerm cPprTermBase t = doc
145 | otherwise = panic "Outputable Term instance"
147 -------------------------------------------------------------------------
148 -- Runtime Closure Datatype and functions for retrieving closure related stuff
149 -------------------------------------------------------------------------
150 data ClosureType = Constr
161 data Closure = Closure { tipe :: ClosureType
163 , infoTable :: StgInfoTable
164 , ptrs :: Array Int HValue
168 instance Outputable ClosureType where
171 #include "../includes/ClosureTypes.h"
173 aP_CODE, pAP_CODE :: Int
179 getClosureData :: a -> IO Closure
181 case unpackClosure# a of
182 (# iptr, ptrs, nptrs #) -> do
183 #ifndef GHCI_TABLES_NEXT_TO_CODE
184 -- the info pointer we get back from unpackClosure# is to the
185 -- beginning of the standard info table, but the Storable instance
186 -- for info tables takes into account the extra entry pointer
187 -- when !tablesNextToCode, so we must adjust here:
188 itbl <- peek (Ptr iptr `plusPtr` negate wORD_SIZE)
190 itbl <- peek (Ptr iptr)
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 (fromIntegral i)
206 | i == THUNK_SELECTOR = ThunkSelector
207 | i == BLACKHOLE = Blackhole
208 | i >= IND && i <= IND_STATIC = Indirection (fromIntegral i)
209 | fromIntegral i == aP_CODE = AP
211 | fromIntegral i == pAP_CODE = PAP
212 | otherwise = Other (fromIntegral i)
214 isConstr, isIndirection, isThunk :: ClosureType -> Bool
215 isConstr Constr = True
218 isIndirection (Indirection _) = True
219 --isIndirection ThunkSelector = True
220 isIndirection _ = False
222 isThunk (Thunk _) = True
223 isThunk ThunkSelector = True
227 isFullyEvaluated :: a -> IO Bool
228 isFullyEvaluated a = do
229 closure <- getClosureData a
231 Constr -> do are_subs_evaluated <- amapM isFullyEvaluated (ptrs closure)
232 return$ and are_subs_evaluated
234 where amapM f = sequence . amap' f
236 amap' :: (t -> b) -> Array Int t -> [b]
237 amap' f (Array i0 i _ arr#) = map g [0 .. i - i0]
238 where g (I# i#) = case indexArray# arr# i# of
241 -- TODO: Fix it. Probably the otherwise case is failing, trace/debug it
243 unsafeDeepSeq :: a -> b -> b
244 unsafeDeepSeq = unsafeDeepSeq1 2
245 where unsafeDeepSeq1 0 a b = seq a $! b
246 unsafeDeepSeq1 i a b -- 1st case avoids infinite loops for non reducible thunks
247 | not (isConstr tipe) = seq a $! unsafeDeepSeq1 (i-1) a b
248 -- | unsafePerformIO (isFullyEvaluated a) = b
249 | otherwise = case unsafePerformIO (getClosureData a) of
250 closure -> foldl' (flip unsafeDeepSeq) b (ptrs closure)
251 where tipe = unsafePerformIO (getClosureType a)
253 isPointed :: Type -> Bool
254 isPointed t | Just (t, _) <- splitTyConApp_maybe t
255 = not$ isUnliftedTypeKind (tyConKind t)
258 extractUnboxed :: [Type] -> Closure -> [[Word]]
259 extractUnboxed tt clos = go tt (nonPtrs clos)
261 | Just (tycon,_) <- splitTyConApp_maybe t
262 = ASSERT (isPrimTyCon tycon) sizeofTyCon tycon
263 | otherwise = pprPanic "Expected a TcTyCon" (ppr t)
266 | (x, rest) <- splitAt ((sizeofType t + wORD_SIZE - 1) `div` wORD_SIZE) xx
269 sizeofTyCon :: TyCon -> Int
270 sizeofTyCon = sizeofPrimRep . tyConPrimRep
272 -----------------------------------
273 -- * Traversals for Terms
274 -----------------------------------
275 type TermProcessor a b = Type -> Either String DataCon -> HValue -> [a] -> b
277 data TermFold a = TermFold { fTerm :: TermProcessor a a
278 , fPrim :: Type -> [Word] -> a
279 , fSuspension :: ClosureType -> Maybe Type -> HValue
281 , fNewtypeWrap :: Type -> Either String DataCon
285 foldTerm :: TermFold a -> Term -> a
286 foldTerm tf (Term ty dc v tt) = fTerm tf ty dc v (map (foldTerm tf) tt)
287 foldTerm tf (Prim ty v ) = fPrim tf ty v
288 foldTerm tf (Suspension ct ty v b) = fSuspension tf ct ty v b
289 foldTerm tf (NewtypeWrap ty dc t) = fNewtypeWrap tf ty dc (foldTerm tf t)
291 idTermFold :: TermFold Term
292 idTermFold = TermFold {
295 fSuspension = Suspension,
296 fNewtypeWrap = NewtypeWrap
298 idTermFoldM :: Monad m => TermFold (m Term)
299 idTermFoldM = TermFold {
300 fTerm = \ty dc v tt -> sequence tt >>= return . Term ty dc v,
301 fPrim = (return.). Prim,
302 fSuspension = (((return.).).). Suspension,
303 fNewtypeWrap= \ty dc t -> NewtypeWrap ty dc `liftM` t
306 mapTermType :: (Type -> Type) -> Term -> Term
307 mapTermType f = foldTerm idTermFold {
308 fTerm = \ty dc hval tt -> Term (f ty) dc hval tt,
309 fSuspension = \ct mb_ty hval n ->
310 Suspension ct (fmap f mb_ty) hval n,
311 fNewtypeWrap= \ty dc t -> NewtypeWrap (f ty) dc t}
313 termTyVars :: Term -> TyVarSet
314 termTyVars = foldTerm TermFold {
315 fTerm = \ty _ _ tt ->
316 tyVarsOfType ty `plusVarEnv` concatVarEnv tt,
317 fSuspension = \_ mb_ty _ _ ->
318 maybe emptyVarEnv tyVarsOfType mb_ty,
319 fPrim = \ _ _ -> emptyVarEnv,
320 fNewtypeWrap= \ty _ t -> tyVarsOfType ty `plusVarEnv` t}
321 where concatVarEnv = foldr plusVarEnv emptyVarEnv
323 ----------------------------------
324 -- Pretty printing of terms
325 ----------------------------------
327 type Precedence = Int
328 type TermPrinter = Precedence -> Term -> SDoc
329 type TermPrinterM m = Precedence -> Term -> m SDoc
331 app_prec,cons_prec, max_prec ::Int
334 cons_prec = 5 -- TODO Extract this info from GHC itself
336 pprTerm :: TermPrinter -> TermPrinter
337 pprTerm y p t | Just doc <- pprTermM (\p -> Just . y p) p t = doc
338 pprTerm _ _ _ = panic "pprTerm"
340 pprTermM, ppr_termM, pprNewtypeWrap :: Monad m => TermPrinterM m -> TermPrinterM m
341 pprTermM y p t = pprDeeper `liftM` ppr_termM y p t
343 pprTermM1, ppr_termM1 :: Monad m => Term -> m SDoc
344 pprTermM1 t = pprDeeper `liftM` ppr_termM1 t
346 ppr_termM y p Term{dc=Left dc_tag, subTerms=tt} = do
347 tt_docs <- mapM (y app_prec) tt
348 return$ cparen (not(null tt) && p >= app_prec) (text dc_tag <+> pprDeeperList fsep tt_docs)
350 ppr_termM y p Term{dc=Right dc, subTerms=tt}
351 {- | dataConIsInfix dc, (t1:t2:tt') <- tt --TODO fixity
352 = parens (ppr_term1 True t1 <+> ppr dc <+> ppr_term1 True ppr t2)
353 <+> hsep (map (ppr_term1 True) tt)
354 -} -- TODO Printing infix constructors properly
355 | null tt = return$ ppr dc
357 tt_docs <- mapM (y app_prec) tt
358 return$ cparen (p >= app_prec) (ppr dc <+> pprDeeperList fsep tt_docs)
360 ppr_termM y p t@NewtypeWrap{} = pprNewtypeWrap y p t
362 ppr_termM _ _ t = ppr_termM1 t
365 ppr_termM1 Prim{value=words, ty=ty} =
366 return$ text$ repPrim (tyConAppTyCon ty) words
367 ppr_termM1 Term{} = panic "ppr_termM1 - unreachable"
368 ppr_termM1 Suspension{bound_to=Nothing} = return$ char '_'
369 ppr_termM1 Suspension{mb_ty=Just ty, bound_to=Just n}
370 | Just _ <- splitFunTy_maybe ty = return$ ptext SLIT("<function>")
371 | otherwise = return$ parens$ ppr n <> text "::" <> ppr ty
372 ppr_termM1 _ = panic "ppr_termM1"
374 pprNewtypeWrap y p NewtypeWrap{ty=ty, wrapped_term=t}
375 | Just (tc,_) <- splitNewTyConApp_maybe ty
376 , ASSERT(isNewTyCon tc) True
377 , Just new_dc <- maybeTyConSingleCon tc = do
378 real_term <- y max_prec t
379 return$ cparen (p >= app_prec) (ppr new_dc <+> real_term)
380 pprNewtypeWrap _ _ _ = panic "pprNewtypeWrap"
382 -------------------------------------------------------
383 -- Custom Term Pretty Printers
384 -------------------------------------------------------
386 -- We can want to customize the representation of a
387 -- term depending on its type.
388 -- However, note that custom printers have to work with
389 -- type representations, instead of directly with types.
390 -- We cannot use type classes here, unless we employ some
391 -- typerep trickery (e.g. Weirich's RepLib tricks),
392 -- which I didn't. Therefore, this code replicates a lot
393 -- of what type classes provide for free.
395 type CustomTermPrinter m = TermPrinterM m
396 -> [Precedence -> Term -> (m (Maybe SDoc))]
398 -- | Takes a list of custom printers with a explicit recursion knot and a term,
399 -- and returns the output of the first succesful printer, or the default printer
400 cPprTerm :: Monad m => CustomTermPrinter m -> Term -> m SDoc
401 cPprTerm printers_ = go 0 where
402 printers = printers_ go
403 go prec t | isTerm t || isNewtypeWrap t = do
404 let default_ = Just `liftM` pprTermM go prec t
405 mb_customDocs = [pp prec t | pp <- printers] ++ [default_]
406 Just doc <- firstJustM mb_customDocs
407 return$ cparen (prec>app_prec+1) doc
410 firstJustM (mb:mbs) = mb >>= maybe (firstJustM mbs) (return . Just)
411 firstJustM [] = return Nothing
413 -- Default set of custom printers. Note that the recursion knot is explicit
414 cPprTermBase :: Monad m => CustomTermPrinter m
416 [ ifTerm (isTupleTy.ty) (\_p -> liftM (parens . hcat . punctuate comma)
419 , ifTerm (\t -> isTyCon listTyCon (ty t) && subTerms t `lengthIs` 2)
420 (\ p Term{subTerms=[h,t]} -> doList p h t)
421 , ifTerm (isTyCon intTyCon . ty) (coerceShow$ \(a::Int)->a)
422 , ifTerm (isTyCon charTyCon . ty) (coerceShow$ \(a::Char)->a)
423 , ifTerm (isTyCon floatTyCon . ty) (coerceShow$ \(a::Float)->a)
424 , ifTerm (isTyCon doubleTyCon . ty) (coerceShow$ \(a::Double)->a)
425 , ifTerm (isIntegerTy . ty) (coerceShow$ \(a::Integer)->a)
427 where ifTerm pred f prec t@Term{}
428 | pred t = Just `liftM` f prec t
429 ifTerm _ _ _ _ = return Nothing
431 isIntegerTy ty = fromMaybe False $ do
432 (tc,_) <- splitTyConApp_maybe ty
433 return (tyConName tc == integerTyConName)
435 isTupleTy ty = fromMaybe False $ do
436 (tc,_) <- splitTyConApp_maybe ty
437 return (tc `elem` (fst.unzip.elems) boxedTupleArr)
439 isTyCon a_tc ty = fromMaybe False $ do
440 (tc,_) <- splitTyConApp_maybe ty
443 coerceShow f _p = return . text . show . f . unsafeCoerce# . val
445 --Note pprinting of list terms is not lazy
447 let elems = h : getListTerms t
448 isConsLast = termType(last elems) /= termType h
449 print_elems <- mapM (y cons_prec) elems
450 return$ if isConsLast
451 then cparen (p >= cons_prec)
453 . punctuate (space<>colon)
455 else brackets (pprDeeperList fcat$
456 punctuate comma print_elems)
458 where Just a /= Just b = not (a `coreEqType` b)
460 getListTerms Term{subTerms=[h,t]} = h : getListTerms t
461 getListTerms Term{subTerms=[]} = []
462 getListTerms t@Suspension{} = [t]
463 getListTerms t = pprPanic "getListTerms" (ppr t)
466 repPrim :: TyCon -> [Word] -> String
467 repPrim t = rep where
469 | t == charPrimTyCon = show (build x :: Char)
470 | t == intPrimTyCon = show (build x :: Int)
471 | t == wordPrimTyCon = show (build x :: Word)
472 | t == floatPrimTyCon = show (build x :: Float)
473 | t == doublePrimTyCon = show (build x :: Double)
474 | t == int32PrimTyCon = show (build x :: Int32)
475 | t == word32PrimTyCon = show (build x :: Word32)
476 | t == int64PrimTyCon = show (build x :: Int64)
477 | t == word64PrimTyCon = show (build x :: Word64)
478 | t == addrPrimTyCon = show (nullPtr `plusPtr` build x)
479 | t == stablePtrPrimTyCon = "<stablePtr>"
480 | t == stableNamePrimTyCon = "<stableName>"
481 | t == statePrimTyCon = "<statethread>"
482 | t == realWorldTyCon = "<realworld>"
483 | t == threadIdPrimTyCon = "<ThreadId>"
484 | t == weakPrimTyCon = "<Weak>"
485 | t == arrayPrimTyCon = "<array>"
486 | t == byteArrayPrimTyCon = "<bytearray>"
487 | t == mutableArrayPrimTyCon = "<mutableArray>"
488 | t == mutableByteArrayPrimTyCon = "<mutableByteArray>"
489 | t == mutVarPrimTyCon= "<mutVar>"
490 | t == mVarPrimTyCon = "<mVar>"
491 | t == tVarPrimTyCon = "<tVar>"
492 | otherwise = showSDoc (char '<' <> ppr t <> char '>')
493 where build ww = unsafePerformIO $ withArray ww (peek . castPtr)
494 -- This ^^^ relies on the representation of Haskell heap values being
495 -- the same as in a C array.
497 -----------------------------------
498 -- Type Reconstruction
499 -----------------------------------
501 Type Reconstruction is type inference done on heap closures.
502 The algorithm walks the heap generating a set of equations, which
503 are solved with syntactic unification.
504 A type reconstruction equation looks like:
506 <datacon reptype> = <actual heap contents>
508 The full equation set is generated by traversing all the subterms, starting
511 The only difficult part is that newtypes are only found in the lhs of equations.
512 Right hand sides are missing them. We can either (a) drop them from the lhs, or
513 (b) reconstruct them in the rhs when possible.
515 The function congruenceNewtypes takes a shot at (b)
518 -- The Type Reconstruction monad
521 runTR :: HscEnv -> TR a -> IO a
523 mb_term <- runTR_maybe hsc_env c
525 Nothing -> panic "Can't unify"
528 runTR_maybe :: HscEnv -> TR a -> IO (Maybe a)
529 runTR_maybe hsc_env = fmap snd . initTc hsc_env HsSrcFile False iNTERACTIVE
531 traceTR :: SDoc -> TR ()
532 traceTR = liftTcM . traceTc
535 trIO = liftTcM . ioToTcRn
537 liftTcM :: TcM a -> TR a
540 newVar :: Kind -> TR TcType
541 newVar = liftTcM . fmap mkTyVarTy . newFlexiTyVar
543 -- | Returns the instantiated type scheme ty', and the substitution sigma
544 -- such that sigma(ty') = ty
545 instScheme :: Type -> TR (TcType, TvSubst)
546 instScheme ty | (tvs, _rho) <- tcSplitForAllTys ty = liftTcM$ do
547 (tvs',_theta,ty') <- tcInstType (mapM tcInstTyVar) ty
548 return (ty', zipTopTvSubst tvs' (mkTyVarTys tvs))
550 -- Adds a constraint of the form t1 == t2
551 -- t1 is expected to come from walking the heap
552 -- t2 is expected to come from a datacon signature
553 -- Before unification, congruenceNewtypes needs to
555 addConstraint :: TcType -> TcType -> TR ()
556 addConstraint t1 t2 = congruenceNewtypes t1 t2 >>= uncurry unifyType
557 >> return () -- TOMDO: what about the coercion?
558 -- we should consider family instances
560 -- Type & Term reconstruction
561 cvObtainTerm :: HscEnv -> Int -> Bool -> Maybe Type -> HValue -> IO Term
562 cvObtainTerm hsc_env bound force mb_ty hval = runTR hsc_env $ do
563 tv <- newVar argTypeKind
565 Nothing -> go bound tv tv hval
567 >>= return . expandNewtypes
568 Just ty | isMonomorphic ty -> go bound ty ty hval
570 >>= return . expandNewtypes
572 (ty',rev_subst) <- instScheme (sigmaType ty)
574 term <- go bound tv tv hval >>= zonkTerm
575 --restore original Tyvars
576 return$ expandNewtypes $ mapTermType (substTy rev_subst) term
578 go bound _ _ _ | seq bound False = undefined
580 clos <- trIO $ getClosureData a
581 return (Suspension (tipe clos) (Just tv) a Nothing)
582 go bound tv ty a = do
583 let monomorphic = not(isTyVarTy tv)
584 -- This ^^^ is a convention. The ancestor tests for
585 -- monomorphism and passes a type instead of a tv
586 clos <- trIO $ getClosureData a
588 -- Thunks we may want to force
589 -- NB. this won't attempt to force a BLACKHOLE. Even with :force, we never
590 -- force blackholes, because it would almost certainly result in deadlock,
591 -- and showing the '_' is more useful.
592 t | isThunk t && force -> seq a $ go (pred bound) tv ty a
593 -- We always follow indirections
594 Indirection _ -> go bound tv ty $! (ptrs clos ! 0)
595 -- The interesting case
597 Right dcname <- dataConInfoPtrToName (infoPtr clos)
598 (_,mb_dc) <- tryTcErrs (tcLookupDataCon dcname)
600 Nothing -> do -- This can happen for private constructors compiled -O0
601 -- where the .hi descriptor does not export them
602 -- In such case, we return a best approximation:
603 -- ignore the unpointed args, and recover the pointeds
604 -- This preserves laziness, and should be safe.
605 let tag = showSDoc (ppr dcname)
606 vars <- replicateM (length$ elems$ ptrs clos)
607 (newVar (liftedTypeKind))
608 subTerms <- sequence [appArr (go (pred bound) tv tv) (ptrs clos) i
609 | (i, tv) <- zip [0..] vars]
610 return (Term tv (Left ('<' : tag ++ ">")) a subTerms)
612 let extra_args = length(dataConRepArgTys dc) -
613 length(dataConOrigArgTys dc)
614 subTtypes = matchSubTypes dc ty
615 (subTtypesP, subTtypesNP) = partition isPointed subTtypes
616 subTermTvs <- sequence
617 [ if isMonomorphic t then return t
619 | (t,k) <- zip subTtypesP (map typeKind subTtypesP)]
620 -- It is vital for newtype reconstruction that the unification step
621 -- is done right here, _before_ the subterms are RTTI reconstructed
622 when (not monomorphic) $ do
623 let myType = mkFunTys (reOrderTerms subTermTvs
627 (signatureType,_) <- instScheme(dataConRepType dc)
628 addConstraint myType signatureType
629 subTermsP <- sequence $ drop extra_args
630 -- ^^^ all extra arguments are pointed
631 [ appArr (go (pred bound) tv t) (ptrs clos) i
632 | (i,tv,t) <- zip3 [0..] subTermTvs subTtypesP]
633 let unboxeds = extractUnboxed subTtypesNP clos
634 subTermsNP = map (uncurry Prim) (zip subTtypesNP unboxeds)
635 subTerms = reOrderTerms subTermsP subTermsNP
636 (drop extra_args subTtypes)
637 return (Term tv (Right dc) a subTerms)
638 -- The otherwise case: can be a Thunk,AP,PAP,etc.
640 return (Suspension tipe_clos (Just tv) a Nothing)
643 | Just (_,ty_args) <- splitTyConApp_maybe (repType ty)
644 -- assumption: ^^^ looks through newtypes
645 , isVanillaDataCon dc --TODO non-vanilla case
646 = dataConInstArgTys dc ty_args
647 | otherwise = dataConRepArgTys dc
649 -- This is used to put together pointed and nonpointed subterms in the
651 reOrderTerms _ _ [] = []
652 reOrderTerms pointed unpointed (ty:tys)
653 | isPointed ty = ASSERT2(not(null pointed)
654 , ptext SLIT("reOrderTerms") $$
655 (ppr pointed $$ ppr unpointed))
656 let (t:tt) = pointed in t : reOrderTerms tt unpointed tys
657 | otherwise = ASSERT2(not(null unpointed)
658 , ptext SLIT("reOrderTerms") $$
659 (ppr pointed $$ ppr unpointed))
660 let (t:tt) = unpointed in t : reOrderTerms pointed tt tys
662 expandNewtypes t@Term{ ty=ty, subTerms=tt }
663 | Just (tc, args) <- splitNewTyConApp_maybe ty
665 , wrapped_type <- newTyConInstRhs tc args
666 , Just dc <- maybeTyConSingleCon tc
667 , t' <- expandNewtypes t{ ty = wrapped_type
668 , subTerms = map expandNewtypes tt }
669 = NewtypeWrap ty (Right dc) t'
671 | otherwise = t{ subTerms = map expandNewtypes tt }
676 -- Fast, breadth-first Type reconstruction
677 cvReconstructType :: HscEnv -> Int -> Maybe Type -> HValue -> IO (Maybe Type)
678 cvReconstructType hsc_env max_depth mb_ty hval = runTR_maybe hsc_env $ do
679 tv <- newVar argTypeKind
681 Nothing -> do search (isMonomorphic `fmap` zonkTcType tv)
683 (Seq.singleton (tv, hval))
685 zonkTcType tv -- TODO untested!
686 Just ty | isMonomorphic ty -> return ty
688 (ty',rev_subst) <- instScheme (sigmaType ty)
690 search (isMonomorphic `fmap` zonkTcType tv)
692 (Seq.singleton (tv, hval))
694 substTy rev_subst `fmap` zonkTcType tv
696 -- search :: m Bool -> ([a] -> [a] -> [a]) -> [a] -> m ()
697 search _ _ _ 0 = traceTR (text "Failed to reconstruct a type after " <>
698 int max_depth <> text " steps")
699 search stop expand l d =
702 x :< xx -> unlessM stop $ do
704 search stop expand (xx `mappend` Seq.fromList new) $! (pred d)
706 -- returns unification tasks,since we are going to want a breadth-first search
707 go :: Type -> HValue -> TR [(Type, HValue)]
709 clos <- trIO $ getClosureData a
711 Indirection _ -> go tv $! (ptrs clos ! 0)
713 Right dcname <- dataConInfoPtrToName (infoPtr clos)
714 (_,mb_dc) <- tryTcErrs (tcLookupDataCon dcname)
717 -- TODO: Check this case
718 forM [0..length (elems $ ptrs clos)] $ \i -> do
719 tv <- newVar liftedTypeKind
720 return$ appArr (\e->(tv,e)) (ptrs clos) i
723 let extra_args = length(dataConRepArgTys dc) -
724 length(dataConOrigArgTys dc)
725 subTtypes <- mapMif (not . isMonomorphic)
726 (\t -> newVar (typeKind t))
727 (dataConRepArgTys dc)
729 -- It is vital for newtype reconstruction that the unification step
730 -- is done right here, _before_ the subterms are RTTI reconstructed
731 let myType = mkFunTys subTtypes tv
732 (signatureType,_) <- instScheme(dataConRepType dc)
733 addConstraint myType signatureType
734 return $ [ appArr (\e->(t,e)) (ptrs clos) i
735 | (i,t) <- drop extra_args $
736 zip [0..] (filter isPointed subTtypes)]
739 -- This helper computes the difference between a base type t and the
740 -- improved rtti_t computed by RTTI
741 -- The main difference between RTTI types and their normal counterparts
742 -- is that the former are _not_ polymorphic, thus polymorphism must
743 -- be stripped. Syntactically, forall's must be stripped.
744 -- We also remove predicates.
745 unifyRTTI :: Type -> Type -> TvSubst
746 unifyRTTI ty rtti_ty =
749 Nothing -> pprPanic "Failed to compute a RTTI substitution"
751 -- In addition, we strip newtypes too, since the reconstructed type might
752 -- not have recovered them all
753 -- TODO stripping newtypes shouldn't be necessary, test
754 where mb_subst = tcUnifyTys (const BindMe)
758 -- Dealing with newtypes
760 A parallel fold over two Type values,
761 compensating for missing newtypes on both sides.
762 This is necessary because newtypes are not present
763 in runtime, but since sometimes there is evidence
764 available we do our best to reconstruct them.
765 Evidence can come from DataCon signatures or
766 from compile-time type inference.
767 I am using the words congruence and rewriting
768 because what we are doing here is an approximation
769 of unification modulo a set of equations, which would
770 come from newtype definitions. These should be the
771 equality coercions seen in System Fc. Rewriting
772 is performed, taking those equations as rules,
773 before launching unification.
775 It doesn't make sense to rewrite everywhere,
776 or we would end up with all newtypes. So we rewrite
777 only in presence of evidence.
778 The lhs comes from the heap structure of ptrs,nptrs.
779 The rhs comes from a DataCon type signature.
780 Rewriting in the rhs is restricted to the result type.
782 Note that it is very tricky to make this 'rewriting'
783 work with the unification implemented by TcM, where
784 substitutions are 'inlined'. The order in which
785 constraints are unified is vital for this.
786 This is a simple form of residuation, the technique of
787 delaying unification steps until enough information
790 congruenceNewtypes :: TcType -> TcType -> TR (TcType,TcType)
791 congruenceNewtypes lhs rhs
792 -- TyVar lhs inductive case
793 | Just tv <- getTyVar_maybe lhs
794 = recoverTc (return (lhs,rhs)) $ do
795 Indirect ty_v <- readMetaTyVar tv
796 (_lhs1, rhs1) <- congruenceNewtypes ty_v rhs
798 -- FunTy inductive case
799 | Just (l1,l2) <- splitFunTy_maybe lhs
800 , Just (r1,r2) <- splitFunTy_maybe rhs
801 = do (l2',r2') <- congruenceNewtypes l2 r2
802 (l1',r1') <- congruenceNewtypes l1 r1
803 return (mkFunTy l1' l2', mkFunTy r1' r2')
804 -- TyconApp Inductive case; this is the interesting bit.
805 | Just (tycon_l, _) <- splitNewTyConApp_maybe lhs
806 , Just (tycon_r, _) <- splitNewTyConApp_maybe rhs
808 = do rhs' <- upgrade tycon_l rhs
811 | otherwise = return (lhs,rhs)
813 where upgrade :: TyCon -> Type -> TR Type
815 | not (isNewTyCon new_tycon) = return ty
817 vars <- mapM (newVar . tyVarKind) (tyConTyVars new_tycon)
818 let ty' = mkTyConApp new_tycon vars
819 liftTcM (unifyType ty (repType ty'))
820 -- assumes that reptype doesn't ^^^^ touch tyconApp args
824 --------------------------------------------------------------------------------
825 -- Semantically different to recoverM in TcRnMonad
826 -- recoverM retains the errors in the first action,
827 -- whereas recoverTc here does not
828 recoverTc :: TcM a -> TcM a -> TcM a
829 recoverTc recover thing = do
830 (_,mb_res) <- tryTcErrs thing
833 Just res -> return res
835 isMonomorphic :: Type -> Bool
836 isMonomorphic ty | (tvs, ty') <- splitForAllTys ty
837 = null tvs && (isEmptyVarSet . tyVarsOfType) ty'
839 mapMif :: Monad m => (a -> Bool) -> (a -> m a) -> [a] -> m [a]
840 mapMif pred f xx = sequence $ mapMif_ pred f xx
843 mapMif_ pred f (x:xx) = (if pred x then f x else return x) : mapMif_ pred f xx
845 unlessM :: Monad m => m Bool -> m () -> m ()
846 unlessM condM acc = condM >>= \c -> unless c acc
848 -- Strict application of f at index i
849 appArr :: Ix i => (e -> a) -> Array i e -> Int -> a
850 appArr f a@(Array _ _ _ ptrs#) i@(I# i#)
851 = ASSERT (i < length(elems a))
852 case indexArray# ptrs# i# of
855 zonkTerm :: Term -> TcM Term
856 zonkTerm = foldTerm idTermFoldM {
857 fTerm = \ty dc v tt -> sequence tt >>= \tt ->
858 zonkTcType ty >>= \ty' ->
859 return (Term ty' dc v tt)
860 ,fSuspension = \ct ty v b -> fmapMMaybe zonkTcType ty >>= \ty ->
861 return (Suspension ct ty v b)
862 ,fNewtypeWrap= \ty dc t ->
863 return NewtypeWrap `ap` zonkTcType ty `ap` return dc `ap` t}
866 -- Is this defined elsewhere?
867 -- Generalize the type: find all free tyvars and wrap in the appropiate ForAll.
868 sigmaType :: Type -> Type
869 sigmaType ty = mkForAllTys (varSetElems$ tyVarsOfType (dropForAlls ty)) ty