Re-working of the breakpoint support
[ghc-hetmet.git] / compiler / ghci / RtClosureInspect.hs
index ef8d367..b12d296 100644 (file)
@@ -10,21 +10,11 @@ module RtClosureInspect(
   
      cvObtainTerm,       -- :: HscEnv -> Bool -> Maybe Type -> HValue -> IO Term
 
-     AddressEnv(..), 
-     DataConEnv,
-     extendAddressEnvList, 
-     elemAddressEnv, 
-     delFromAddressEnv, 
-     emptyAddressEnv, 
-     lookupAddressEnv, 
-
      ClosureType(..), 
-     getClosureData, 
-     Closure ( tipe, infoTable, ptrs, nonPtrs ), 
-     getClosureType, 
-     isConstr, 
-     isIndirection,
-     getInfoTablePtr, 
+     getClosureData,     -- :: a -> IO Closure
+     Closure ( tipe, infoPtr, ptrs, nonPtrs ), 
+     isConstr,           -- :: ClosureType -> Bool
+     isIndirection,      -- :: ClosureType -> Bool
 
      Term(..), 
      printTerm, 
@@ -61,7 +51,6 @@ import Name
 import VarEnv
 import OccName
 import VarSet
-import Unique
 import {-#SOURCE#-} TcRnDriver ( tcRnRecoverDataCon )
 
 import TysPrim         
@@ -86,6 +75,8 @@ import Data.Array.Base
 import Data.List        ( partition )
 import Foreign.Storable
 
+import IO
+
 ---------------------------------------------
 -- * A representation of semi evaluated Terms
 ---------------------------------------------
@@ -125,6 +116,11 @@ isPrim   _    = False
 termType t@(Suspension {}) = mb_ty t
 termType t = Just$ ty t
 
+isFullyEvaluatedTerm :: Term -> Bool
+isFullyEvaluatedTerm Term {subTerms=tt} = all isFullyEvaluatedTerm tt
+isFullyEvaluatedTerm Suspension {}      = False
+isFullyEvaluatedTerm Prim {}            = True
+
 instance Outputable (Term) where
  ppr = head . customPrintTerm customPrintTermBase
 
@@ -143,6 +139,7 @@ data ClosureType = Constr
  deriving (Show, Eq)
 
 data Closure = Closure { tipe         :: ClosureType 
+                       , infoPtr      :: Ptr ()
                        , infoTable    :: StgInfoTable
                        , ptrs         :: Array Int HValue
                         -- What would be the type here? HValue is ok? Should I build a Ptr?
@@ -152,14 +149,6 @@ data Closure = Closure { tipe         :: ClosureType
 instance Outputable ClosureType where
   ppr = text . show 
 
-getInfoTablePtr :: a -> Ptr StgInfoTable
-getInfoTablePtr x = 
-    case infoPtr# x of
-      itbl_ptr -> castPtr ( Ptr itbl_ptr )
-
-getClosureType :: a -> IO ClosureType
-getClosureType = liftM (readCType . BCI.tipe ) . peek . getInfoTablePtr
-
 #include "../includes/ClosureTypes.h"
 
 aP_CODE = AP
@@ -168,14 +157,14 @@ pAP_CODE = PAP
 #undef PAP
 
 getClosureData :: a -> IO Closure
-getClosureData a = do
-   itbl <- peek (getInfoTablePtr a)
-   let tipe = readCType (BCI.tipe itbl)
-   case closurePayload# a of 
-     (# ptrs, nptrs #) -> 
-           let elems = BCI.ptrs itbl 
+getClosureData a =
+   case unpackClosure# a of 
+     (# iptr, ptrs, nptrs #) -> do
+           itbl <- peek (Ptr iptr)
+           let tipe = readCType (BCI.tipe itbl)
+               elems = BCI.ptrs itbl 
                ptrsList = Array 0 (fromIntegral$ elems) ptrs
-           in ptrsList `seq` return (Closure tipe itbl ptrsList nptrs)
+           ptrsList `seq` return (Closure tipe (Ptr iptr) itbl ptrsList nptrs)
 
 readCType :: Integral a => a -> ClosureType
 readCType i
@@ -270,7 +259,7 @@ extractUnboxed tt ba = helper tt (byteArrayContents# ba)
            -- TODO: Improve the offset handling in decode (make it machine dependant)
 
 -----------------------------------
--- Boilerplate Fold code for Term
+-- * Traversals for Terms
 -----------------------------------
 
 data TermFold a = TermFold { fTerm :: Type -> DataCon -> HValue -> [a] -> a
@@ -309,8 +298,9 @@ printTerm :: Term -> SDoc
 printTerm Prim{value=value} = text value 
 printTerm t@Term{} = printTerm1 0 t 
 printTerm Suspension{bound_to=Nothing} =  char '_' -- <> ppr ct <> char '_'
-printTerm Suspension{mb_ty=Just ty, bound_to=Just n} =
-  parens$ ppr n <> text "::" <> ppr ty 
+printTerm Suspension{mb_ty=Just ty, bound_to=Just n}
+  | Just _ <- splitFunTy_maybe ty = text "<function>"
+  | otherwise = parens$ ppr n <> text "::" <> ppr ty 
 
 printTerm1 p Term{dc=dc, subTerms=tt} 
 {-  | dataConIsInfix dc, (t1:t2:tt') <- tt 
@@ -358,7 +348,7 @@ customPrintTermBase showP =
                                     , largeIntegerDataConName] 
            isTupleDC Term{dc=dc}   = dc `elem` snd (unzip (elems boxedTupleArr))
            isDC a_dc Term{dc=dc}   = a_dc == dc
-           coerceShow f Term{val=val} = return . text . show . f . unsafeCoerce# $ val
+           coerceShow f = return . text . show . f . unsafeCoerce# . val
            --TODO pprinting of list terms is not lazy
            doList h t = do
                let elems = h : getListTerms t
@@ -379,12 +369,6 @@ customPrintTermBase showP =
                       getListTerms t@Suspension{}       = [t]
                       getListTerms t = pprPanic "getListTerms" (ppr t)
 
-isFullyEvaluatedTerm :: Term -> Bool
-isFullyEvaluatedTerm Term {subTerms=tt} = all isFullyEvaluatedTerm tt
-isFullyEvaluatedTerm Suspension {}      = False
-isFullyEvaluatedTerm Prim {}            = True
-
-
 -----------------------------------
 -- Type Reconstruction
 -----------------------------------
@@ -403,45 +387,81 @@ trIO :: IO a -> TR a
 trIO = liftTcM . ioToTcRn
 
 addConstraint :: TcType -> TcType -> TR ()
-addConstraint t1 t2  = congruenceNewtypes t1 t2 >> unifyType t1 t2
-
--- A parallel fold over a Type value, replacing
--- in the right side reptypes for newtypes as found in the lhs
--- Sadly it doesn't cover all the possibilities. It does not always manage
--- to recover the highest level type. See test print016 for an example
-congruenceNewtypes ::  TcType -> TcType -> TcM TcType
-congruenceNewtypes lhs rhs
---    | pprTrace "Congruence" (ppr lhs $$ ppr rhs) False = undefined
- -- We have a tctyvar at the other side
+addConstraint t1 t2  = congruenceNewtypes t1 t2 >>= uncurry unifyType 
+
+{-
+   A parallel fold over two Type values, 
+ compensating for missing newtypes on both sides. 
+ This is necessary because newtypes are not present 
+ in runtime, but since sometimes there is evidence 
+ available we do our best to reconstruct them. 
+   Evidence can come from DataCon signatures or 
+ from compile-time type inference.
+   I am using the words congruence and rewriting 
+ because what we are doing here is an approximation 
+ of unification modulo a set of equations, which would 
+ come from newtype definitions. These should be the 
+ equality coercions seen in System Fc. Rewriting 
+ is performed, taking those equations as rules, 
+ before launching unification.
+
+   It doesn't make sense to rewrite everywhere, 
+ or we would end up with all newtypes. So we rewrite 
+ only in presence of evidence.
+   The lhs comes from the heap structure of ptrs,nptrs. 
+   The rhs comes from a DataCon type signature. 
+ Rewriting in the rhs is restricted to the result type.
+
+   Note that it is very tricky to make this 'rewriting'
+ work with the unification implemented by TcM, where
+ substitutions are 'inlined'. The order in which 
+ constraints are unified is vital for this (or I am 
+ using TcM wrongly).
+-}
+congruenceNewtypes ::  TcType -> TcType -> TcM (TcType,TcType)
+congruenceNewtypes = go True
+  where 
+   go rewriteRHS lhs rhs  
+ -- TyVar lhs inductive case
+    | Just tv <- getTyVar_maybe lhs 
+    = recoverM (return (lhs,rhs)) $ do  
+         Indirect ty_v <- readMetaTyVar tv
+         (lhs', rhs') <- go rewriteRHS ty_v rhs
+         writeMutVar (metaTvRef tv) (Indirect lhs')
+         return (lhs, rhs')
+ -- TyVar rhs inductive case
     | Just tv <- getTyVar_maybe rhs 
---    , trace "congruence, entering tyvar" True
-    = recoverM (return rhs) $ do  
+    = recoverM (return (lhs,rhs)) $ do  
          Indirect ty_v <- readMetaTyVar tv
-         newtyped_tytv <- congruenceNewtypes lhs ty_v
-         writeMutVar (metaTvRef tv) (Indirect newtyped_tytv)
-         return newtyped_tytv
--- We have a function type: go on inductively
-    | Just (r1,r2) <- splitFunTy_maybe rhs
-    , Just (l1,l2) <- splitFunTy_maybe lhs
-    = liftM2 mkFunTy ( congruenceNewtypes l1 r1)
-                      (congruenceNewtypes l2 r2)
--- There is a newtype at the top level tycon and we can manage it
-    | Just (tycon, args)    <- splitNewTyConApp_maybe lhs
-    , isNewTyCon tycon
-    , (tvs, realtipe)       <- newTyConRep tycon
-    =   case tcUnifyTys (const BindMe) [realtipe] [rhs] of
-          Just subst -> 
-                let tvs' = substTys subst (map mkTyVarTy tvs) in
-                liftM (mkTyConApp tycon) (zipWithM congruenceNewtypes args tvs')
-          otherwise -> panic "congruenceNewtypes: Can't unify a newtype"
-                                             
--- We have a TyconApp: go on inductively
-    | Just (tycon, args)     <- splitNewTyConApp_maybe lhs
-    , Just (tycon_v, args_v) <- splitNewTyConApp_maybe rhs
-    = liftM (mkTyConApp tycon_v) (zipWithM congruenceNewtypes args args_v)
-
-    | otherwise = return rhs
-
+         (lhs', rhs') <- go rewriteRHS lhs ty_v
+         writeMutVar (metaTvRef tv) (Indirect rhs')
+         return (lhs', rhs)
+-- FunTy inductive case
+    | Just (l1,l2) <- splitFunTy_maybe lhs
+    , Just (r1,r2) <- splitFunTy_maybe rhs
+    = do (l2',r2') <- go True l2 r2
+         (l1',r1') <- go False l1 r1
+         return (mkFunTy l1' l2', mkFunTy r1' r2')
+-- TyconApp Inductive case; this is the interesting bit.
+    | Just (tycon_l, args_l) <- splitNewTyConApp_maybe lhs
+    , Just (tycon_r, args_r) <- splitNewTyConApp_maybe rhs = do
+
+      let (tycon_l',args_l') = if isNewTyCon tycon_r && not(isNewTyCon tycon_l)
+                                then (tycon_r, rewrite tycon_r lhs)
+                                else (tycon_l, args_l)
+          (tycon_r',args_r') = if rewriteRHS && isNewTyCon tycon_l && not(isNewTyCon tycon_r)
+                                then (tycon_l, rewrite tycon_l rhs)
+                                else (tycon_r, args_r)
+      (args_l'', args_r'') <- unzip `liftM` zipWithM (go rewriteRHS) args_l' args_r'
+      return (mkTyConApp tycon_l' args_l'', mkTyConApp tycon_r' args_r'') 
+
+    | otherwise = return (lhs,rhs)
+
+    where rewrite newtyped_tc lame_tipe
+           | (tvs, tipe) <- newTyConRep newtyped_tc 
+           = case tcUnifyTys (const BindMe) [tipe] [lame_tipe] of
+               Just subst -> substTys subst (map mkTyVarTy tvs)
+               otherwise  -> panic "congruenceNewtypes: Can't unify a newtype"
 
 newVar :: Kind -> TR TcTyVar
 newVar = liftTcM . newFlexiTyVar
@@ -454,9 +474,10 @@ instScheme ty = liftTcM$ liftM trd (tcInstType (liftM fst3 . tcInstTyVars) ty)
           trd  (x,y,z) = z
 
 cvObtainTerm :: HscEnv -> Bool -> Maybe Type -> HValue -> IO Term
-cvObtainTerm hsc_env force mb_ty a = 
- -- Obtain the term and tidy the type before returning it
-     cvObtainTerm1 hsc_env force mb_ty a >>= return . tidyTypes 
+cvObtainTerm hsc_env force mb_ty a = do
+   -- Obtain the term and tidy the type before returning it
+   term <- cvObtainTerm1 hsc_env force mb_ty a
+   return $ tidyTypes term
    where 
          tidyTypes = foldTerm idTermFold {
             fTerm = \ty dc hval tt -> Term (tidy ty) dc hval tt,
@@ -465,66 +486,55 @@ cvObtainTerm hsc_env force mb_ty a =
             }
          tidy ty = tidyType (emptyTidyOccEnv, tidyVarEnv ty) ty  
          tidyVarEnv ty = 
+
              mkVarEnv$ [ (v, setTyVarName v (tyVarName tv))
                          | (tv,v) <- zip alphaTyVars vars]
              where vars = varSetElems$ tyVarsOfType ty
 
 cvObtainTerm1 :: HscEnv -> Bool -> Maybe Type -> HValue -> IO Term
-cvObtainTerm1 hsc_env force mb_ty hval
-  | Nothing <- mb_ty = runTR hsc_env . go argTypeKind $ hval
-  | Just ty <- mb_ty = runTR hsc_env $ do
-                 term <- go argTypeKind hval
-                 ty'  <- instScheme ty
-                 addConstraint ty' (fromMaybe (error "by definition") 
-                                              (termType term)) 
-                 return term
+cvObtainTerm1 hsc_env force mb_ty hval = runTR hsc_env $ do
+   tv   <- liftM mkTyVarTy (newVar argTypeKind)
+   when (isJust mb_ty) $ 
+        instScheme (sigmaType$ fromJust mb_ty) >>= addConstraint tv
+   go tv hval
     where 
-  go k a = do 
-    ctype <- trIO$ getClosureType a
-    case ctype of
+  go tv a = do 
+    clos <- trIO $ getClosureData a
+    case tipe clos of
 -- Thunks we may want to force
-      Thunk _ | force -> seq a $ go k a
+      Thunk _ | force -> seq a $ go tv a
 -- We always follow indirections 
-      _       | isIndirection ctype 
-                      -> do
-        clos   <- trIO$ getClosureData a
---      dflags <- getSessionDynFlags session
---      debugTraceMsg dflags 2 (text "Following an indirection")
-        go k $! (ptrs clos ! 0)
+      Indirection _ -> go tv $! (ptrs clos ! 0)
  -- The interesting case
       Constr -> do
-        m_dc <- trIO$ tcRnRecoverDataCon hsc_env a
+        m_dc <- trIO$ tcRnRecoverDataCon hsc_env (infoPtr clos)
         case m_dc of
           Nothing -> panic "Can't find the DataCon for a term"
           Just dc -> do 
-            clos          <- trIO$ getClosureData a
             let extra_args = length(dataConRepArgTys dc) - length(dataConOrigArgTys dc)
                 subTtypes  = drop extra_args (dataConRepArgTys dc)
                 (subTtypesP, subTtypesNP) = partition isPointed subTtypes
-                
-            subTermsP <- mapM (\i->extractSubterm i (ptrs clos)
-                                                    (subTtypesP!!(i-extra_args)))
-                              [extra_args..extra_args + length subTtypesP - 1]
+                n_subtermsP= length subTtypesP
+            subTermTvs    <- mapM (liftM mkTyVarTy . newVar ) (map typeKind subTtypesP)
+            baseType      <- instScheme (dataConRepType dc)
+            let myType     = mkFunTys (reOrderTerms subTermTvs subTtypesNP subTtypes) tv
+            addConstraint myType baseType
+            subTermsP <- sequence [ extractSubterm i tv (ptrs clos) 
+                                   | (i,tv) <- zip [extra_args..extra_args + n_subtermsP - 1]
+                                                   subTermTvs ]
             let unboxeds   = extractUnboxed subTtypesNP (nonPtrs clos)
                 subTermsNP = map (uncurry Prim) (zip subTtypesNP unboxeds)      
                 subTerms   = reOrderTerms subTermsP subTermsNP subTtypes
-            resType       <- liftM mkTyVarTy (newVar k)
-            baseType      <- instScheme (dataConRepType dc)
-            let myType     = mkFunTys (map (fromMaybe undefined . termType) 
-                                       subTerms) 
-                                  resType
-            addConstraint baseType myType
-            return (Term resType dc a subTerms)
+            return (Term tv dc a subTerms)
 -- The otherwise case: can be a Thunk,AP,PAP,etc.
       otherwise -> do
-         x <- liftM mkTyVarTy (newVar k)
-         return (Suspension ctype (Just x) a Nothing)
+         return (Suspension (tipe clos) (Just tv) a Nothing)
 
 -- Access the array of pointers and recurse down. Needs to be done with
 -- care of no introducing a thunk! or go will fail to do its job 
-  extractSubterm (I# i#) ptrs ty = case ptrs of 
+  extractSubterm (I# i#) tv ptrs = case ptrs of 
                  (Array _ _ ptrs#) -> case indexArray# ptrs# i# of 
-                       (# e #) -> go (typeKind ty) e
+                       (# e #) -> go tv e
 
 -- This is used to put together pointed and nonpointed subterms in the 
 --  correct order.
@@ -541,6 +551,11 @@ zonkTerm = foldTerm idTermFoldM {
              ,fSuspension = \ct ty v b -> fmapMMaybe zonkTcType ty >>= \ty ->
                                           return (Suspension ct ty v b)}  
 
+
+-- Is this defined elsewhere?
+-- Generalize the type: find all free tyvars and wrap in the appropiate ForAll.
+sigmaType ty = mkForAllTys (varSetElems$ tyVarsOfType (dropForAlls ty)) ty
+
 {-
 Example of Type Reconstruction
 --------------------------------
@@ -591,34 +606,3 @@ map Just [[1,1],[2,2]] :: [Maybe [Integer]]
 
 NOTE: (Num t) contexts have been manually replaced by Integer for clarity
 -}
-
---------------------------------------------------------------------
--- The DataConEnv is used to store the addresses of datacons loaded
--- via the dynamic linker
---------------------------------------------------------------------
-
-type DataConEnv   = AddressEnv StgInfoTable
-
--- Note that this AddressEnv and DataConEnv I wrote trying to follow 
--- conventions in ghc, but probably they make not much sense.
-
-newtype AddressEnv a = AE {aenv:: FiniteMap (Ptr a) Name}
-  deriving (Outputable)
-
-emptyAddressEnv = AE emptyFM
-
-extendAddressEnvList  :: AddressEnv a -> [(Ptr a, Name)] -> AddressEnv a
-elemAddressEnv        :: Ptr a -> AddressEnv a -> Bool
-delFromAddressEnv     :: AddressEnv a -> Ptr a -> AddressEnv a
-nullAddressEnv        :: AddressEnv a -> Bool
-lookupAddressEnv       :: AddressEnv a -> Ptr a -> Maybe Name
-
-extendAddressEnvList  (AE env) = AE . addListToFM env 
-elemAddressEnv   ptr  (AE env) = ptr `elemFM` env
-delFromAddressEnv     (AE env) = AE . delFromFM env
-nullAddressEnv                 = isEmptyFM . aenv
-lookupAddressEnv      (AE env) = lookupFM env
-
-
-instance Outputable (Ptr a) where
-  ppr = text . show