{-# LANGUAGE LambdaCase #-} module Intensional.FromCore ( freshCoreType, freshCoreScheme, fromCoreCons, consInstArgs, getVar, ) where import Control.Monad.RWS import qualified Data.IntSet as I import qualified Data.Map as M import GhcPlugins hiding ((<>), Expr (..), Type) import Intensional.InferM import Intensional.Scheme as Scheme import ToIface import qualified TyCoRep as Tcr import Intensional.Types -- A fresh monomorphic type freshCoreType :: Tcr.Type -> InferM Type freshCoreType = fromCore Nothing -- A fresh polymorphic type freshCoreScheme :: Tcr.Type -> InferM Scheme freshCoreScheme = fromCoreScheme Nothing -- The type of a constructor injected into a fresh refinement environment fromCoreCons :: DataCon -> InferM Scheme fromCoreCons k = do x <- fresh let d = dataConTyCon k b <- isIneligible d unless b $ do l <- asks inferLoc emitKD k l (Inj x d) fromCoreScheme (Just x) (dataConUserType k) -- The argument types of an instantiated constructor consInstArgs :: RVar -> [Type] -> DataCon -> InferM [Type] consInstArgs x as k = mapM fromCoreInst (dataConRepArgTys k) where fromCoreInst :: Tcr.Type -> InferM Type fromCoreInst (Tcr.TyVarTy a) = case lookup a (zip (dataConUnivTyVars k) as) of Nothing -> return (Var (getName a)) Just t -> return t fromCoreInst (Tcr.AppTy a b) = App <$> (fromCoreInst a) <*> (fromCoreInst b) fromCoreInst (Tcr.TyConApp d as') | isTypeSynonymTyCon d, Just (as'', s) <- synTyConDefn_maybe d = fromCoreInst (substTy (extendTvSubstList emptySubst (zip as'' as')) s) -- Instantiate type synonym arguments | isClassTyCon d = return Ambiguous -- Disregard type class evidence | otherwise = do b <- isIneligible d if b then Data (Base d) <$> (mapM fromCoreInst as') else Data (Inj x d) <$> (mapM fromCoreInst as') fromCoreInst (Tcr.FunTy a b) = (:=>) <$> fromCoreInst a <*> fromCoreInst b fromCoreInst (Tcr.LitTy l) = return (Lit $ toIfaceTyLit l) fromCoreInst _ = return Ambiguous -- Convert a monomorphic core type fromCore :: Maybe RVar -> Tcr.Type -> InferM Type fromCore _ (Tcr.TyVarTy a) = Var <$> getExternalName a fromCore f (Tcr.AppTy a b) = liftM2 App (fromCore f a) (fromCore f b) fromCore f (Tcr.TyConApp d as) | isTypeSynonymTyCon d, Just (as', s) <- synTyConDefn_maybe d = fromCore f (substTy (extendTvSubstList emptySubst (zip as' as)) s) -- Instantiate type synonyms | isClassTyCon d = return Ambiguous -- Disregard type class evidence fromCore Nothing (Tcr.TyConApp d as) = do x <- fresh b <- isIneligible d if b then Data (Base d) <$> mapM (fromCore Nothing) as else Data (Inj x d) <$> mapM (fromCore Nothing) as fromCore (Just x) (Tcr.TyConApp d as) = do b <- isIneligible d if b then Data (Base d) <$> mapM (fromCore (Just x)) as else Data (Inj x d) <$> mapM (fromCore (Just x)) as fromCore f (Tcr.FunTy a b) = liftM2 (:=>) (fromCore f a) (fromCore f b) fromCore _ (Tcr.LitTy l) = return $ Lit $ toIfaceTyLit l fromCore _ _ = return Ambiguous -- Higher-ranked or impredicative types, casts and coercions -- Convert a polymorphic core type fromCoreScheme :: Maybe RVar -> Tcr.Type -> InferM Scheme fromCoreScheme f (Tcr.ForAllTy b t) = do a <- getExternalName (Tcr.binderVar b) scheme <- fromCoreScheme f t return scheme {tyvars = a : tyvars scheme} fromCoreScheme f (Tcr.FunTy a b) = do a' <- fromCore f a scheme <- fromCoreScheme f b -- Optimistically push arrows inside univiersal quantifier return scheme {body = a' :=> body scheme} fromCoreScheme f t = Forall [] <$> fromCore f t -- Lookup constrained variable and emit its constraints getVar :: Var -> InferM Scheme getVar v = asks (M.lookup (getName v) . varEnv) >>= \case Just scheme -> do -- Localise constraints fre_scheme <- foldM ( \s x -> do y <- fresh return (rename x y s) ) (scheme {boundvs = mempty}) (I.toList (boundvs scheme)) -- Emit constriants associated with a variable tell (constraints fre_scheme) return fre_scheme {Scheme.constraints = mempty} Nothing -> do var_scheme <- freshCoreScheme $ varType v maximise True (body var_scheme) return var_scheme -- Maximise/minimise a library type, i.e. assert every constructor occurs in covariant positions maximise :: Bool -> Type -> InferM () maximise True (Data (Inj x d) _) = do l <- asks inferLoc mapM_ (\k -> emitKD k l (Inj x d)) $ tyConDataCons d maximise b (x :=> y) = maximise (not b) x >> maximise b y maximise _ _ = return ()