mapTermType,
termTyVars,
-- unsafeDeepSeq,
- reconstructType
+ cvReconstructType
) where
#include "HsVersions.h"
import DataCon
import Type
-import TcRnMonad ( TcM, initTcPrintErrors, ioToTcRn, recoverM, writeMutVar )
+import TcRnMonad ( TcM, initTcPrintErrors, ioToTcRn, recoverM
+ , writeMutVar )
import TcType
import TcMType
import TcUnify
import Name
import VarEnv
import OccName
+import Util
import VarSet
import {-#SOURCE#-} TcRnDriver ( tcRnRecoverDataCon )
import Data.Array.Base
import Data.List ( partition, nub )
import Foreign
+import System.IO.Unsafe
---------------------------------------------
-- * A representation of semi evaluated Terms
-}
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] }
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
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
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]]
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
-- 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)
getListTerms t@Suspension{} = [t]
getListTerms t = pprPanic "getListTerms" (ppr t)
+
repPrim :: TyCon -> [Word] -> String
repPrim t = rep where
rep x
| 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
(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
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
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 ->
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
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
--- Fast, breadth-first version of obtainTerm that deals only with type reconstruction
+-- Fast, breadth-first Type reconstruction
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)]
+ 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)]
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
+ search stop expand [] = return ()
+ search stop expand (x:xx) = do new <- expand x
+ unlessM stop $ search stop expand (xx ++ new)
- -- returns unification tasks, since we are going to want a breadth-first search
+ -- 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
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))
+ -- 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 $ map (\(I# i#,t) -> case ptrs clos of
+ (Array _ _ ptrs#) -> case indexArray# ptrs# i# of
+ (# e #) -> (t,e))
(drop extra_args $ zip [0..] subTtypes)
otherwise -> return []
using TcM wrongly).
-}
congruenceNewtypes :: TcType -> TcType -> TcM (TcType,TcType)
-congruenceNewtypes = go True
- where
- go rewriteRHS lhs rhs
+congruenceNewtypes 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)
+ (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') <- go True l2 r2
- (l1',r1') <- go False l1 r1
+ = 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 = 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'')
+ , Just (tycon_r, args_r) <- splitNewTyConApp_maybe rhs
+ , tycon_l /= tycon_r
+ = return (lhs, upgrade tycon_l rhs)
| 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"
+ 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'