Ask for a HscEnv instead of a Session in InteractiveEval.obtainTerm
[ghc-hetmet.git] / compiler / ghci / RtClosureInspect.hs
index 3ca0b0b..19403ae 100644 (file)
@@ -25,7 +25,7 @@ module RtClosureInspect(
      mapTermType,
      termTyVars,
 --     unsafeDeepSeq, 
-     reconstructType
+     cvReconstructType
  ) where 
 
 #include "HsVersions.h"
@@ -37,7 +37,8 @@ import HscTypes         ( HscEnv )
 
 import DataCon          
 import Type             
-import TcRnMonad        ( TcM, initTcPrintErrors, ioToTcRn, recoverM, writeMutVar )
+import TcRnMonad        ( TcM, initTcPrintErrors, ioToTcRn, recoverM
+                        , writeMutVar )
 import TcType
 import TcMType
 import TcUnify
@@ -47,6 +48,7 @@ import Var
 import Name 
 import VarEnv
 import OccName
+import Util
 import VarSet
 import {-#SOURCE#-} TcRnDriver ( tcRnRecoverDataCon )
 
@@ -69,6 +71,7 @@ import Data.Maybe
 import Data.Array.Base
 import Data.List        ( partition, nub )
 import Foreign
+import System.IO.Unsafe
 
 ---------------------------------------------
 -- * A representation of semi evaluated Terms
@@ -86,7 +89,8 @@ import Foreign
 -}
 
 data Term = Term { ty        :: Type 
-                 , dc        :: DataCon 
+                 , dc        :: DataCon  -- The heap datacon. If ty is a newtype,
+                                         -- this is NOT the newtype datacon
                  , val       :: HValue 
                  , subTerms  :: [Term] }
 
@@ -158,7 +162,8 @@ getClosureData a =
                ptrsList = Array 0 (fromIntegral$ elems) ptrs
                nptrs_data = [W# (indexWordArray# nptrs i)
                               | I# i <- [0.. fromIntegral (BCI.nptrs itbl)] ]
-           ptrsList `seq` return (Closure tipe (Ptr iptr) itbl ptrsList nptrs_data)
+           ptrsList `seq` 
+            return (Closure tipe (Ptr iptr) itbl ptrsList nptrs_data)
 
 readCType :: Integral a => a -> ClosureType
 readCType i
@@ -204,7 +209,7 @@ amap' f (Array i0 i arr#) = map (\(I# i#) -> case indexArray# arr# i# of
 unsafeDeepSeq :: a -> b -> b
 unsafeDeepSeq = unsafeDeepSeq1 2
  where unsafeDeepSeq1 0 a b = seq a $! b
-       unsafeDeepSeq1 i a b                -- 1st case avoids infinite loops for non reducible thunks
+       unsafeDeepSeq1 i a b   -- 1st case avoids infinite loops for non reducible thunks
         | not (isConstr tipe) = seq a $! unsafeDeepSeq1 (i-1) a b     
      -- | unsafePerformIO (isFullyEvaluated a) = b
         | otherwise = case unsafePerformIO (getClosureData a) of
@@ -212,7 +217,8 @@ unsafeDeepSeq = unsafeDeepSeq1 2
         where tipe = unsafePerformIO (getClosureType a)
 -}
 isPointed :: Type -> Bool
-isPointed t | Just (t, _) <- splitTyConApp_maybe t = not$ isUnliftedTypeKind (tyConKind t)
+isPointed t | Just (t, _) <- splitTyConApp_maybe t 
+            = not$ isUnliftedTypeKind (tyConKind t)
 isPointed _ = True
 
 extractUnboxed  :: [Type] -> Closure -> [[Word]]
@@ -234,7 +240,8 @@ sizeofTyCon = sizeofPrimRep . tyConPrimRep
 
 data TermFold a = TermFold { fTerm :: Type -> DataCon -> HValue -> [a] -> a
                            , fPrim :: Type -> [Word] -> a
-                           , fSuspension :: ClosureType -> Maybe Type -> HValue -> Maybe Name -> a
+                           , fSuspension :: ClosureType -> Maybe Type -> HValue
+                                           -> Maybe Name -> a
                            }
 
 foldTerm :: TermFold a -> Term -> a
@@ -271,73 +278,83 @@ termTyVars = foldTerm TermFold {
 -- Pretty printing of terms
 ----------------------------------
 
-app_prec::Int
+app_prec,cons_prec ::Int
 app_prec = 10
+cons_prec = 5 -- TODO Extract this info from GHC itself
 
-pprTerm :: Int -> Term -> SDoc
-pprTerm p Term{dc=dc, subTerms=tt} 
-{-  | dataConIsInfix dc, (t1:t2:tt') <- tt 
+pprTerm y p t | Just doc <- pprTermM y p t = doc
+
+pprTermM :: Monad m => (Int -> Term -> m SDoc) -> Int -> Term -> m SDoc
+pprTermM y p t@Term{dc=dc, subTerms=tt, ty=ty} 
+{-  | dataConIsInfix dc, (t1:t2:tt') <- tt  --TODO fixity
   = parens (pprTerm1 True t1 <+> ppr dc <+> pprTerm1 True ppr t2) 
     <+> hsep (map (pprTerm1 True) tt) 
 -}
-  | null tt   = ppr dc
-  | otherwise = cparen (p >= app_prec) 
-                       (ppr dc <+> sep (map (pprTerm app_prec) tt))
-
-  where fixity   = undefined 
-
-pprTerm _ t = pprTerm1 t
-
-pprTerm1 Prim{value=words, ty=ty} = text$ repPrim (tyConAppTyCon ty) words
-pprTerm1 t@Term{} = pprTerm 0 t 
-pprTerm1 Suspension{bound_to=Nothing} =  char '_' -- <> ppr ct <> char '_'
-pprTerm1 Suspension{mb_ty=Just ty, bound_to=Just n}
-  | Just _ <- splitFunTy_maybe ty = ptext SLIT("<function>")
-  | otherwise = parens$ ppr n <> text "::" <> ppr ty 
-
-
-cPprTerm :: forall m. Monad m => ((Int->Term->m SDoc)->[Int->Term->m (Maybe SDoc)]) -> Term -> m SDoc
+  | null tt   = return$ ppr dc
+  | Just (tc,_) <- splitNewTyConApp_maybe ty
+  , isNewTyCon tc
+  , Just new_dc <- maybeTyConSingleCon tc = do 
+         real_value <- y 10 t{ty=repType ty}
+         return$ cparen (p >= app_prec) (ppr new_dc <+> real_value)
+  | otherwise = do
+         tt_docs <- mapM (y app_prec) tt
+         return$ cparen (p >= app_prec) (ppr dc <+> sep tt_docs)
+
+pprTermM y _ t = pprTermM1 y t
+
+pprTermM1 _ Prim{value=words, ty=ty} = return$ text$ repPrim (tyConAppTyCon ty)
+                                                             words
+pprTermM1 y t@Term{} = panic "pprTermM1 - unreachable"
+pprTermM1 _ Suspension{bound_to=Nothing} = return$ char '_'
+pprTermM1 _ Suspension{mb_ty=Just ty, bound_to=Just n}
+  | Just _ <- splitFunTy_maybe ty = return$ ptext SLIT("<function>")
+  | otherwise = return$ parens$ ppr n <> text "::" <> ppr ty 
+
+-- Takes a list of custom printers with a explicit recursion knot and a term, 
+-- and returns the output of the first succesful printer, or the default printer
+cPprTerm :: forall m. Monad m => 
+           ((Int->Term->m SDoc)->[Int->Term->m (Maybe SDoc)]) -> Term -> m SDoc
 cPprTerm custom = go 0 where
   go prec t@Term{subTerms=tt, dc=dc} = do
-    let mb_customDocs = map (($t) . ($prec)) (custom go) :: [m (Maybe SDoc)]    
-    first_success <- firstJustM mb_customDocs
-    case first_success of
-      Just doc -> return$ cparen (prec>app_prec+1) doc
---    | dataConIsInfix dc, (t1:t2:tt') <- tt =
-      Nothing  -> do pprSubterms <- mapM (go (app_prec+1)) tt
-                     return$ cparen (prec >= app_prec) 
-                                    (ppr dc <+> sep pprSubterms)
-  go _ t = return$ pprTerm1 t
+    let default_ prec t = Just `liftM` pprTermM go prec t
+        mb_customDocs = [pp prec t | pp <- custom go ++ [default_]]
+    Just doc <- firstJustM mb_customDocs
+    return$ cparen (prec>app_prec+1) doc
+  go _ t = pprTermM1 go t
   firstJustM (mb:mbs) = mb >>= maybe (firstJustM mbs) (return . Just)
   firstJustM [] = return Nothing
 
+-- Default set of custom printers. Note that the recursion knot is explicit
 cPprTermBase :: Monad m => (Int->Term-> m SDoc)->[Int->Term->m (Maybe SDoc)]
-cPprTermBase pprP =
+cPprTermBase y =
   [ 
-    ifTerm isTupleDC            (\_ -> liftM (parens . hcat . punctuate comma) 
-                                 . mapM (pprP (-1)) . subTerms)
-  , ifTerm (isDC consDataCon)   (\ p Term{subTerms=[h,t]} -> doList p h t)
-  , ifTerm (isDC intDataCon)    (coerceShow$ \(a::Int)->a)
-  , ifTerm (isDC charDataCon)   (coerceShow$ \(a::Char)->a)
---  , ifTerm (isDC wordDataCon) (coerceShow$ \(a::Word)->a)
-  , ifTerm (isDC floatDataCon)  (coerceShow$ \(a::Float)->a)
-  , ifTerm (isDC doubleDataCon) (coerceShow$ \(a::Double)->a)
-  , ifTerm isIntegerDC          (coerceShow$ \(a::Integer)->a)
+    ifTerm isTupleTy             (\_ -> liftM (parens . hcat . punctuate comma) 
+                                 . mapM (y (-1)) . subTerms)
+  , ifTerm (\t -> isTyCon listTyCon t && subTerms t `lengthIs` 2)
+                                 (\ p Term{subTerms=[h,t]} -> doList p h t)
+  , ifTerm (isTyCon intTyCon)    (coerceShow$ \(a::Int)->a)
+  , ifTerm (isTyCon charTyCon)   (coerceShow$ \(a::Char)->a)
+--  , ifTerm (isTyCon wordTyCon) (coerceShow$ \(a::Word)->a)
+  , ifTerm (isTyCon floatTyCon)  (coerceShow$ \(a::Float)->a)
+  , ifTerm (isTyCon doubleTyCon) (coerceShow$ \(a::Double)->a)
+  , ifTerm isIntegerTy           (coerceShow$ \(a::Integer)->a)
   ] 
-     where ifTerm pred f p t = if pred t then liftM Just (f p t) else return Nothing
-           isIntegerDC Term{dc=dc} = 
-              dataConName dc `elem` [ smallIntegerDataConName
-                                    , largeIntegerDataConName] 
-           isTupleDC Term{dc=dc} = dc `elem` snd (unzip (elems boxedTupleArr))
-           isDC a_dc Term{dc=dc} = a_dc == dc
+     where ifTerm pred f p t@Term{} | pred t    = liftM Just (f p t) 
+                                    | otherwise = return Nothing
+           isIntegerTy Term{ty=ty}  | Just (tc,_) <- splitTyConApp_maybe ty 
+                                    = tyConName tc == integerTyConName
+           isTupleTy Term{ty=ty}    | Just (tc,_) <- splitTyConApp_maybe ty 
+                                    = tc `elem` (fst.unzip.elems) boxedTupleArr
+           isTyCon a_tc Term{ty=ty} | Just (tc,_) <- splitTyConApp_maybe ty
+                                    = a_tc == tc
            coerceShow f _ = return . text . show . f . unsafeCoerce# . val
            --TODO pprinting of list terms is not lazy
            doList p h t = do
                let elems = h : getListTerms t
                    isConsLast = termType(last elems) /= termType h
-               print_elems <- mapM (pprP 5) elems
+               print_elems <- mapM (y cons_prec) elems
                return$ if isConsLast
-                     then cparen (p >= 5) . hsep . punctuate (space<>colon) 
+                     then cparen (p >= cons_prec) . hsep . punctuate (space<>colon) 
                            $ print_elems
                      else brackets (hcat$ punctuate comma print_elems)
 
@@ -348,6 +365,7 @@ cPprTermBase pprP =
                       getListTerms t@Suspension{}       = [t]
                       getListTerms t = pprPanic "getListTerms" (ppr t)
 
+
 repPrim :: TyCon -> [Word] -> String
 repPrim t = rep where 
    rep x
@@ -376,9 +394,29 @@ repPrim t = rep where
     | t == tVarPrimTyCon  = "<tVar>"
     | otherwise = showSDoc (char '<' <> ppr t <> char '>')
     where build ww = unsafePerformIO $ withArray ww (peek . castPtr) 
+--   This ^^^ relies on the representation of Haskell heap values being 
+--   the same as in a C array. 
+
 -----------------------------------
 -- Type Reconstruction
 -----------------------------------
+{-
+Type Reconstruction is type inference done on heap closures.
+The algorithm walks the heap generating a set of equations, which
+are solved with syntactic unification.
+A type reconstruction equation looks like:
+
+  <datacon reptype>  =  <actual heap contents> 
+
+The full equation set is generated by traversing all the subterms, starting
+from a given term.
+
+The only difficult part is that newtypes are only found in the lhs of equations.
+Right hand sides are missing them. We can either (a) drop them from the lhs, or 
+(b) reconstruct them in the rhs when possible. 
+
+The function congruenceNewtypes takes a shot at (b)
+-}
 
 -- The Type Reconstruction monad
 type TR a = TcM a
@@ -393,88 +431,11 @@ runTR hsc_env c = do
 trIO :: IO a -> TR a 
 trIO = liftTcM . ioToTcRn
 
-addConstraint :: TcType -> TcType -> TR ()
-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 
-    = recoverM (return (lhs,rhs)) $ do  
-         Indirect ty_v <- readMetaTyVar tv
-         (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"
+liftTcM = id
 
 newVar :: Kind -> TR TcTyVar
 newVar = liftTcM . newFlexiTyVar
 
-liftTcM = id
-
 -- | Returns the instantiated type scheme ty', and the substitution sigma 
 --   such that sigma(ty') = ty 
 instScheme :: Type -> TR (TcType, TvSubst)
@@ -482,6 +443,17 @@ instScheme ty | (tvs, rho) <- tcSplitForAllTys ty = liftTcM$ do
    (tvs',theta,ty') <- tcInstType (mapM tcInstTyVar) ty
    return (ty', zipTopTvSubst tvs' (mkTyVarTys tvs))
 
+-- Adds a constraint of the form t1 == t2
+-- t1 is expected to come from walking the heap
+-- t2 is expected to come from a datacon signature
+-- Before unification, congruenceNewtypes needs to
+-- do its magic.
+addConstraint :: TcType -> TcType -> TR ()
+addConstraint t1 t2  = congruenceNewtypes t1 t2 >>= uncurry unifyType 
+
+
+
+-- Type & Term reconstruction 
 cvObtainTerm :: HscEnv -> Bool -> Maybe Type -> HValue -> IO Term
 cvObtainTerm hsc_env force mb_ty hval = runTR hsc_env $ do
    tv <- liftM mkTyVarTy (newVar argTypeKind)
@@ -496,8 +468,9 @@ cvObtainTerm hsc_env force mb_ty hval = runTR hsc_env $ do
               return$ mapTermType (substTy rev_subst) term
     where 
   go tv ty a = do 
-    let monomorphic = not(isTyVarTy tv)   -- This is a convention. The ancestor tests for
-                                         -- monomorphism and passes a type instead of a tv
+    let monomorphic = not(isTyVarTy tv)   
+    -- This ^^^ is a convention. The ancestor tests for
+    -- monomorphism and passes a type instead of a tv
     clos <- trIO $ getClosureData a
     case tipe clos of
 -- Thunks we may want to force
@@ -513,23 +486,31 @@ cvObtainTerm hsc_env force mb_ty hval = runTR hsc_env $ do
         case m_dc of
           Nothing -> panic "Can't find the DataCon for a term"
           Just dc -> do 
-            let extra_args = length(dataConRepArgTys dc) - length(dataConOrigArgTys dc)
+            let extra_args = length(dataConRepArgTys dc) - 
+                             length(dataConOrigArgTys dc)
                 subTtypes  = matchSubTypes dc ty
                 (subTtypesP, subTtypesNP) = partition isPointed subTtypes
             subTermTvs <- sequence
-                 [ if isMonomorphic t then return t else (mkTyVarTy `fmap` newVar k)
+                 [ if isMonomorphic t then return t 
+                                      else (mkTyVarTy `fmap` newVar k)
                    | (t,k) <- zip subTtypesP (map typeKind subTtypesP)]
-            -- It is vital for newtype reconstruction that the unification step is done
-            --     right here, _before_ the subterms are RTTI reconstructed.
+            -- It is vital for newtype reconstruction that the unification step
+            --  is done right here, _before_ the subterms are RTTI reconstructed
             when (not monomorphic) $ do
-                  let myType = mkFunTys (reOrderTerms subTermTvs subTtypesNP subTtypes) tv
-                  instScheme(dataConRepType dc) >>= addConstraint myType . fst
-            subTermsP <- sequence $ drop extra_args -- all extra arguments are pointed
+                  let myType = mkFunTys (reOrderTerms subTermTvs 
+                                                      subTtypesNP 
+                                                      subTtypes) 
+                                        tv
+                  (signatureType,_) <- instScheme(dataConRepType dc) 
+                  addConstraint myType signatureType
+            subTermsP <- sequence $ drop extra_args 
+                                 -- ^^^  all extra arguments are pointed
                   [ appArr (go tv t) (ptrs clos) i
                    | (i,tv,t) <- zip3 [0..] subTermTvs subTtypesP]
             let unboxeds   = extractUnboxed subTtypesNP clos
                 subTermsNP = map (uncurry Prim) (zip subTtypesNP unboxeds)      
-                subTerms   = reOrderTerms subTermsP subTermsNP (drop extra_args subTtypes)
+                subTerms   = reOrderTerms subTermsP subTermsNP 
+                                (drop extra_args subTtypes)
             return (Term tv dc a subTerms)
 -- The otherwise case: can be a Thunk,AP,PAP,etc.
       otherwise -> 
@@ -537,9 +518,9 @@ cvObtainTerm hsc_env force mb_ty hval = runTR hsc_env $ do
 
   matchSubTypes dc ty
     | Just (_,ty_args) <- splitTyConApp_maybe (repType ty) 
-    , null (dataConExTyVars dc)  --TODO Handle the case of extra existential tyvars
+    , isVanillaDataCon dc  --TODO non-vanilla case
     = dataConInstArgTys dc ty_args
-
+--     assumes that newtypes are looked ^^^ through
     | otherwise = dataConRepArgTys dc
 
 -- This is used to put together pointed and nonpointed subterms in the 
@@ -547,36 +528,46 @@ cvObtainTerm hsc_env force mb_ty hval = runTR hsc_env $ do
   reOrderTerms _ _ [] = []
   reOrderTerms pointed unpointed (ty:tys) 
    | isPointed ty = ASSERT2(not(null pointed)
-                           , ptext SLIT("reOrderTerms") $$ (ppr pointed $$ ppr unpointed))
+                            , ptext SLIT("reOrderTerms") $$ 
+                                        (ppr pointed $$ ppr unpointed))
                     head pointed : reOrderTerms (tail pointed) unpointed tys
    | otherwise    = ASSERT2(not(null unpointed)
-                           , ptext SLIT("reOrderTerms") $$ (ppr pointed $$ ppr unpointed))
+                           , ptext SLIT("reOrderTerms") $$ 
+                                       (ppr pointed $$ ppr unpointed))
                     head unpointed : reOrderTerms pointed (tail unpointed) tys
 
--- Strict application of f at index i
-appArr f (Array _ _ ptrs#) (I# i#) = case indexArray# ptrs# i# of 
-                                       (# e #) -> f e
 
--- Fast, breadth-first version of obtainTerm that deals only with type reconstruction
+
+-- Fast, breadth-first Type reconstruction
+max_depth = 10 :: Int
 cvReconstructType :: HscEnv -> Bool -> Maybe Type -> HValue -> IO Type
 cvReconstructType hsc_env force mb_ty hval = runTR hsc_env $ do
    tv <- liftM mkTyVarTy (newVar argTypeKind)
    case mb_ty of
-     Nothing -> search (isMonomorphic `fmap` zonkTcType tv) (++) [(tv, hval)] >> 
-                zonkTcType tv  -- TODO untested!
+     Nothing -> do search (isMonomorphic `fmap` zonkTcType tv)
+                          (uncurry go)  
+                          [(tv, hval)]  
+                          max_depth
+                   zonkTcType tv  -- TODO untested!
      Just ty | isMonomorphic ty -> return ty
      Just ty -> do 
               (ty',rev_subst) <- instScheme (sigmaType ty)
               addConstraint tv ty'
-              search (isMonomorphic `fmap` zonkTcType tv) (++) [(tv, hval)]
+              search (isMonomorphic `fmap` zonkTcType tv) 
+                     (uncurry go) 
+                     [(tv, hval)]
+                     max_depth
               substTy rev_subst `fmap` zonkTcType tv
     where 
 --  search :: m Bool -> ([a] -> [a] -> [a]) -> [a] -> m ()
-  search stop combine []     = return ()
-  search stop combine ((t,a):jj) =  (jj `combine`) `fmap` go t a >>= 
-                                    unlessM stop . search stop combine
-
-   -- returns unification tasks, since we are going to want a breadth-first search
+  search stop expand [] depth  = return ()
+  search stop expand x 0 = fail$ "Failed to reconstruct a type after " ++
+                                show max_depth ++ " steps"
+  search stop expand (x:xx) d  = do 
+    new <- expand x 
+    unlessM stop $ search stop expand (xx ++ new) $! (pred d)
+
+   -- returns unification tasks,since we are going to want a breadth-first search
   go :: Type -> HValue -> TR [(Type, HValue)]
   go tv a = do 
     clos <- trIO $ getClosureData a
@@ -587,21 +578,84 @@ cvReconstructType hsc_env force mb_ty hval = runTR hsc_env $ do
         case m_dc of
           Nothing -> panic "Can't find the DataCon for a term"
           Just dc -> do 
-            let extra_args = length(dataConRepArgTys dc) - length(dataConOrigArgTys dc)
+            let extra_args = length(dataConRepArgTys dc) - 
+                             length(dataConOrigArgTys dc)
             subTtypes <- mapMif (not . isMonomorphic)
                                 (\t -> mkTyVarTy `fmap` newVar (typeKind t))
                                 (dataConRepArgTys dc)
-            -- It is vital for newtype reconstruction that the unification step is done
-            --     right here, _before_ the subterms are RTTI reconstructed.
-            let myType = mkFunTys subTtypes tv
-            fst `fmap` instScheme(dataConRepType dc) >>= addConstraint myType
-            return $map (\(I# i#,t) -> case ptrs clos of 
-                                       (Array _ _ ptrs#) -> case indexArray# ptrs# i# of 
-                                                              (# e #) -> (t,e))
-                        (drop extra_args $ zip [0..] subTtypes)
+            -- It is vital for newtype reconstruction that the unification step
+            -- is done right here, _before_ the subterms are RTTI reconstructed
+            let myType         = mkFunTys subTtypes tv
+            (signatureType,_) <- instScheme(dataConRepType dc) 
+            addConstraint myType signatureType
+            return $ [ appArr (\e->(t,e)) (ptrs clos) i
+                       | (i,t) <- drop extra_args $ zip [0..] subTtypes]
       otherwise -> return []
 
 
+-- Dealing with newtypes
+{-
+   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 lhs rhs 
+ -- TyVar lhs inductive case
+    | Just tv <- getTyVar_maybe lhs 
+    = recoverM (return (lhs,rhs)) $ do  
+         Indirect ty_v <- readMetaTyVar tv
+         (lhs1, rhs1) <- congruenceNewtypes ty_v rhs
+         return (lhs, rhs1)
+-- FunTy inductive case
+    | Just (l1,l2) <- splitFunTy_maybe lhs
+    , Just (r1,r2) <- splitFunTy_maybe rhs
+    = do (l2',r2') <- congruenceNewtypes l2 r2
+         (l1',r1') <- congruenceNewtypes 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 
+    , tycon_l /= tycon_r 
+    = return (lhs, upgrade tycon_l rhs)
+
+    | otherwise = return (lhs,rhs)
+
+    where upgrade :: TyCon -> Type -> Type
+          upgrade new_tycon ty
+            | not (isNewTyCon new_tycon) = ty 
+            | ty' <- mkTyConApp new_tycon (map mkTyVarTy $ tyConTyVars new_tycon)
+            , Just subst <- tcUnifyTys (const BindMe) [ty] [repType ty']
+            = substTy subst ty'
+        -- assumes that reptype doesn't touch tyconApp args ^^^
+
+
+--------------------------------------------------------------------------------
+
 isMonomorphic ty | (tvs, ty') <- splitForAllTys ty
                  = null tvs && (isEmptyVarSet . tyVarsOfType) ty'
 
@@ -612,6 +666,10 @@ mapMif_ pred f (x:xx) = (if pred x then f x else return x) : mapMif_ pred f xx
 
 unlessM condM acc = condM >>= \c -> unless c acc
 
+-- Strict application of f at index i
+appArr f (Array _ _ ptrs#) (I# i#) = case indexArray# ptrs# i# of 
+                                       (# e #) -> f e
+
 zonkTerm :: Term -> TcM Term
 zonkTerm = foldTerm idTermFoldM {
               fTerm = \ty dc v tt -> sequence tt      >>= \tt ->
@@ -625,53 +683,4 @@ zonkTerm = foldTerm idTermFoldM {
 -- 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
---------------------------------
-Suppose we have an existential type such as
-
-data Opaque = forall a. Opaque a
-
-And we have a term built as:
-
-t = Opaque (map Just [[1,1],[2,2]])
 
-The type of t as far as the typechecker goes is t :: Opaque
-If we seq the head of t, we obtain:
-
-t - O (_1::a) 
-
-seq _1 ()
-
-t - O ( (_3::b) : (_4::[b]) ) 
-
-seq _3 ()
-
-t - O ( (Just (_5::c)) : (_4::[b]) ) 
-
-At this point, we know that b = (Maybe c)
-
-seq _5 ()
-
-t - O ( (Just ((_6::d) : (_7::[d]) )) : (_4::[b]) )
-
-At this point, we know that c = [d]
-
-seq _6 ()
-
-t - O ( (Just (1 : (_7::[d]) )) : (_4::[b]) )
-
-At this point, we know that d = Integer
-
-The fully reconstructed expressions, with propagation, would be:
-
-t - O ( (Just (_5::c)) : (_4::[Maybe c]) ) 
-t - O ( (Just ((_6::d) : (_7::[d]) )) : (_4::[Maybe [d]]) )
-t - O ( (Just (1 : (_7::[Integer]) )) : (_4::[Maybe [Integer]]) )
-
-
-For reference, the type of the thing inside the opaque is 
-map Just [[1,1],[2,2]] :: [Maybe [Integer]]
-
-NOTE: (Num t) contexts have been manually replaced by Integer for clarity
--}