module Tip.RemoveDefault where
import Tip.DataConPattern
import Tip.GHCUtils
import CoreSyn
import CoreUtils hiding (findAlt)
import DataCon
import FastString
import TyCon
import Type
import Unique
import UniqSupply
import Id
import Control.Monad
import Control.Applicative
removeDefaults :: (Applicative m,MonadUnique m) => [CoreBind] -> m [CoreBind]
removeDefaults = mapM rmdBind
rmdBind :: (Applicative m,MonadUnique m) => CoreBind -> m CoreBind
rmdBind (NonRec f e) = NonRec f <$> rmdExpr e
rmdBind (Rec fses) = Rec <$> mapM (\ (f,e) -> (,) f <$> rmdExpr e) fses
rmdExpr :: (Applicative m,MonadUnique m) => CoreExpr -> m CoreExpr
rmdExpr e0 = case e0 of
App e1 e2 -> App <$> rmdExpr e1 <*> rmdExpr e2
Lam x e -> Lam x <$> rmdExpr e
Let b e -> Let <$> rmdBind b <*> rmdExpr e
Case s t w alts -> Case <$> rmdExpr s <.> t <.> w
<*> (mapM rmdAlt <=< unrollDefault (exprType s)) alts
Cast e c -> Cast <$> rmdExpr e <.> c
Tick t e -> Tick t <$> rmdExpr e
Type{} -> return e0
Var{} -> return e0
Lit{} -> return e0
Coercion{} -> return e0
rmdAlt :: (Applicative m,MonadUnique m) => CoreAlt -> m CoreAlt
rmdAlt (ac,bs,rhs) = (,,) ac bs <$> rmdExpr rhs
infixl 4 <.>
(<.>) :: Applicative f => f (a -> b) -> a -> f b
f <.> x = f <*> pure x
unrollDefault :: forall m . (Applicative m,MonadUnique m) => Type -> [CoreAlt] -> m [CoreAlt]
unrollDefault t alts0 = case findDefault alts0 of
(alts,Just def_rhs) -> case alts of
(DataAlt dc,_,_):_ | missing (dataConTyCon dc) alts <= 1 -> unroll (dataConTyCon dc) alts def_rhs
(LitAlt _ ,_,_):_ -> return alts0
(DEFAULT ,_,_):_ -> error "RemoveDefault.unrollDefault: duplicate DEFAULT"
_ -> return alts0
(alts,_) -> return alts
where
missing :: TyCon -> [CoreAlt] -> Int
missing ty_con alts = case tyConDataCons_maybe ty_con of
Just dcs -> sum [ 1 | Nothing <- map (findAlt alts) dcs ]
Nothing -> error "RemoveDefault.unrollDefault: non-data TyCon?"
unroll :: TyCon -> [CoreAlt] -> CoreExpr -> m [CoreAlt]
unroll ty_con alts rhs = case tyConDataCons_maybe ty_con of
Just dcs -> forM dcs $ \ dc ->
fromMaybeM (makeAlt t rhs dc) (findAlt alts dc)
Nothing -> error "RemoveDefault.unrollDefault: non-data TyCon?"
findAlt :: [CoreAlt] -> DataCon -> Maybe CoreAlt
findAlt (alt@(DataAlt dc',_,_):_) dc | dc' == dc = Just alt
findAlt (_:alts) dc = findAlt alts dc
findAlt [] _ = Nothing
fromMaybeM :: (Applicative m,MonadUnique m) => Monad m => m a -> Maybe a -> m a
fromMaybeM _ (Just x) = return x
fromMaybeM m Nothing = m
makeAlt :: (Applicative m,MonadUnique m) => Type -> CoreExpr -> DataCon -> m CoreAlt
makeAlt t rhs dc = case dcAppliedTo t dc of
(_,Just s) -> do
bound <- mapM (\ ty -> dummy_var (substTy s ty) <$> getUniqueM) (dataConRepArgTys dc)
return (DataAlt dc,bound,rhs)
_ -> error $ "RemoveDefault.makeAlt unification error:"
++ "\n\t" ++ showOutputable t
++ "\n\t" ++ showOutputable dc
where
dummy_var :: Type -> Unique -> Var
dummy_var ty u = mkSysLocal (fsLit "d") u ty