ddc-core-0.4.3.1: DDC/Core/Check/Context/Apply.hs
module DDC.Core.Check.Context.Apply
( applyContextEither
, applySolvedEither)
where
import DDC.Core.Check.Context.Elem
import DDC.Core.Check.Context.Base
import DDC.Type.Exp.Simple
import qualified DDC.Type.Sum as Sum
import Data.Set (Set)
import Data.Maybe
import qualified Data.IntMap.Strict as IntMap
import qualified Data.Set as Set
import Prelude hiding ((<$>))
-- | Apply a context to a type, updating any existentials in the type. This
-- uses just the solved constraints on the stack, but not in the solved set.
--
-- If we find a loop through the existential equations then
-- return `Left` the existential and what is was locally bound to.
--
applyContextEither
:: Ord n
=> Context n -- ^ Type checker context.
-> Set Int -- ^ Indexes of existentials we've already entered.
-> Type n -- ^ Type to apply context to.
-> Either (Type n, Type n) (Type n)
applyContextEither ctx is tt
= case tt of
TVar{}
-> return tt
TCon (TyConExists i k)
| Just t <- lookupExistsEq (Exists i k) ctx
-> if Set.member i is
then Left (tt, t)
else applyContextEither ctx (Set.insert i is) t
TCon{}
-> return tt
TAbs b t
-> do tb' <- applySolvedEither ctx is (typeOfBind b)
let b' = replaceTypeOfBind tb' b
t' <- applySolvedEither ctx is t
return $ TAbs b' t'
TApp t1 t2
-> do t1' <- applySolvedEither ctx is t1
t2' <- applySolvedEither ctx is t2
return $ TApp t1' t2'
TForall b t
-> do tb' <- applySolvedEither ctx is (typeOfBind b)
let b' = replaceTypeOfBind tb' b
t' <- applySolvedEither ctx is t
return $ TForall b' t'
TSum ts
-> do tss' <- mapM (applyContextEither ctx is)
$ Sum.toList ts
return $ TSum
$ Sum.fromList (Sum.kindOfSum ts) tss'
-- | Like `applyContextEither`, but for the solved types.
applySolvedEither
:: Ord n
=> Context n -- ^ Type checker context.
-> Set Int -- ^ Indexes of existentials we've already entered.
-> Type n -- ^ Type to apply context to.
-> Either (Type n, Type n) (Type n)
applySolvedEither ctx is tt
= case tt of
TVar{}
-> return tt
TCon (TyConExists i k)
| Just t <- IntMap.lookup i (contextSolved ctx)
-> if Set.member i is
then Left (tt, t)
else applySolvedEither ctx (Set.insert i is) t
| Just t <- lookupExistsEq (Exists i k) ctx
-> if Set.member i is
then Left (tt, t)
else applySolvedEither ctx (Set.insert i is) t
TCon {}
-> return tt
TAbs b t
-> do tb' <- applySolvedEither ctx is (typeOfBind b)
let b' = replaceTypeOfBind tb' b
t' <- applySolvedEither ctx is t
return $ TAbs b' t'
TApp t1 t2
-> do t1' <- applySolvedEither ctx is t1
t2' <- applySolvedEither ctx is t2
return $ TApp t1' t2'
TForall b t
-> do tb' <- applySolvedEither ctx is (typeOfBind b)
let b' = replaceTypeOfBind tb' b
t' <- applySolvedEither ctx is t
return $ TForall b' t'
TSum ts
-> do tss' <- mapM (applySolvedEither ctx is)
$ Sum.toList ts
return $ TSum
$ Sum.fromList (Sum.kindOfSum ts) tss'