MiniAgda-0.2014.9.12: TCM.hs
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, PatternGuards, FlexibleContexts, NamedFieldPuns, DeriveFunctor, DeriveFoldable, DeriveTraversable, TupleSections #-}
module TCM where
import Prelude hiding (null)
import Control.Monad
import Control.Monad.Identity
import Control.Monad.State
import Control.Monad.Except
import Control.Monad.Reader
import Control.Applicative
import Data.Foldable (Foldable)
import qualified Data.Foldable as Foldable
import Data.Traversable (Traversable)
import qualified Data.Traversable as Traversable
import Data.Monoid
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import Debug.Trace
import Abstract
import Polarity
import Value
import {-# SOURCE #-} Eval -- (up,whnf')
import PrettyTCM
-- import CallStack
import TraceError
import TreeShapedOrder (TSO)
import qualified TreeShapedOrder as TSO
import Util
import Warshall
-- traceSig msg a = trace msg a
traceSig msg a = a
traceRew msg a = a -- trace msg a
traceRewM msg = return () -- traceM msg
{-
traceRew msg a = trace msg a
traceRewM msg = traceM msg
-}
-- metavariables and constraints
traceMeta msg a = a -- trace msg a
traceMetaM msg = return () -- traceM msg
{-
traceMeta msg a = trace msg a
traceMetaM msg = traceM msg
-}
-- type checking monad -----------------------------------------------
class (MonadCxt m, MonadSig m, MonadMeta m, MonadError TraceError m) =>
MonadTCM m where
-- lists of exactly one or two elements ------------------------------
-- this would have been better implemented by just lists and a view
-- type OneOrTwo a = [a]
-- data View12 a = One a | Two a a
-- fromList12
-- then one could still get completeness of pattern matching!
-- now we have lots of boilerplate code
data OneOrTwo a = One a | Two a a deriving (Eq, Ord, Functor, Foldable, Traversable)
instance Show a => Show (OneOrTwo a) where
show (One a) = show a
show (Two a b) = show a ++ "||" ++ show b
name12 :: OneOrTwo Name -> Name
name12 (One n) = n
name12 (Two n1 n2)
| null (suggestion n2) = n1
| null (suggestion n1) = n2
| suggestion n1 == suggestion n2 = n1
| otherwise = fresh (suggestion n1 ++ "||" ++ suggestion n2)
{-
instance Functor OneOrTwo where
fmap f (One a) = One (f a)
fmap f (Two a b) = Two (f a) (f b)
instance Foldable OneOrTwo where
foldMap f (One a) = f a
foldMap f (Two a b) = f a `mappend` f b
-- traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
instance Traversable OneOrTwo where
traverse f (One a) = One <$> f a
traverse f (Two a b) = Two <$> f a <*> f b
-}
-- eliminator
oneOrTwo :: (a -> b) -> (a -> a -> b) -> OneOrTwo a -> b
oneOrTwo f g (One a) = f a
oneOrTwo f g (Two a1 a2) = g a1 a2
fromOne :: OneOrTwo a -> a
fromOne (One a) = a
toTwo :: OneOrTwo a -> OneOrTwo a
toTwo = oneOrTwo (\ a -> Two a a) Two
first12 :: OneOrTwo a -> a
first12 (One a) = a
first12 (Two a1 a2) = a1
second12 :: OneOrTwo a -> a
second12 (One a) = a
second12 (Two a1 a2) = a2
mapSecond12 :: (a -> a) -> OneOrTwo a -> OneOrTwo a
mapSecond12 f (One a) = One (f a)
mapSecond12 f (Two a1 a2) = Two a1 (f a2)
zipWith12 :: (a -> b -> c) -> OneOrTwo a -> OneOrTwo b -> OneOrTwo c
zipWith12 f (One a) (One b) = One (f a b)
zipWith12 f (Two a a') (Two b b') = Two (f a b) (f a' b')
zipWith123 :: (a -> b -> c -> d) ->
OneOrTwo a -> OneOrTwo b -> OneOrTwo c -> OneOrTwo d
zipWith123 f (One a) (One b) (One c) = One (f a b c)
zipWith123 f (Two a a') (Two b b') (Two c c') = Two (f a b c) (f a' b' c')
toList12 :: OneOrTwo a -> [a]
toList12 (One a) = [a]
toList12 (Two a1 a2) = [a1,a2]
fromList12 :: Show a => [a] -> OneOrTwo a
fromList12 [a] = One a
fromList12 [a1,a2] = Two a1 a2
fromList12 l = error $ "fromList12 " ++ show l
toMaybe12 :: Show a => [a] -> Maybe (OneOrTwo a)
toMaybe12 [] = Nothing
toMaybe12 [a] = Just $ One a
toMaybe12 [a1,a2] = Just $ Two a1 a2
toMaybe12 l = error $ "toMaybe12 " ++ show l
-- reader monad for local environment
data TCContext = TCContext
{ context :: SemCxt
, renaming :: Ren -- assigning de Bruijn Levels to names
, naming :: Map Int Name -- assigning names to de Bruijn levels
-- , nameVariants :: Map Name Int -- how many variants of the name
, environ :: Env2
, rewrites :: Rewrites
, sizeRels :: TSO Int -- relations of universal (rigid) size variables
-- collected from size patterns (x > y)
, belowInfty:: [Int] -- list of size variables < #
, bounds :: [Bound Val] -- bound hyps that do not fit in sizeRels
, consistencyCheck :: Bool -- ^ Do we need to check that new size relations are consistent with every valuation of the current @sizeRels@? [See ICFP 2013 paper]
, checkingConType :: Bool -- different PTS rules for constructor types (parametric function space!)
, assertionHandling :: AssertionHandling -- recover from errors?
, impredicative :: Bool -- use impredicative PTS rules
-- checking measured functions
, funsTemplate :: Map Name (Kinded Fun) -- types of mutual funs with measures checking body
, mutualFuns :: Map Name SigDef -- types of mutual funs while checking body
, mutualCo :: Co -- mutual block (co)recursive ?
, mutualNames :: [Name] -- ^ The defined names of the current mutual block (and parents).
, checkingMutualName :: Maybe DefId -- which body of a mutual block am I checking?
, callStack :: [QName] -- ^ Used to avoid looping when going into recursive data definitions.
}
instance Show TCContext where
show ce = show (environ ce) ++ "; " ++ show (context ce)
emptyContext = TCContext
{ context = cxtEmpty
, renaming = Map.empty
, naming = Map.empty
, environ = emptyEnv
, rewrites = emptyRewrites
, sizeRels = TSO.empty
, belowInfty = []
, bounds = []
, consistencyCheck = False -- initially, no consistency check, turned on when entering rhs
, checkingConType = False
, assertionHandling = Failure -- default is not to ignore any errors
, impredicative = False
, funsTemplate = Map.empty
, mutualFuns = Map.empty
, mutualCo = Ind
, mutualNames = []
, checkingMutualName = Nothing
, callStack = []
}
-- state monad for global signature
data TCState = TCState
{ signature :: Signature
, metaVars :: MetaVars
, constraints :: Constraints
, positivityGraph :: PositivityGraph
-- , dots :: Dots -- UNUSED
}
type MetaVars = Map MVar MetaVar
emptyMetaVars = Map.empty
type MScope = [Name] -- ^ names of size variables which are in scope of mvar
data MetaVar = MetaVar
{ mscope :: MScope
, solution :: Maybe Val
}
type PosConstrnt = Constrnt PPoly DefId ()
type PositivityGraph = [PosConstrnt]
emptyPosGraph = []
-- type TypeCheck = StateT TCState (ReaderT TCContext (CallStackT String IO))
type TypeCheck = StateT TCState (ReaderT TCContext (ExceptT TraceError IO))
instance MonadAssert TypeCheck where
assert b s = do
h <- asks assertionHandling
assert' h b s
newAssertionHandling h = local ( \ ce -> ce { assertionHandling = h })
{- mtl-2 provides these instances
-- TypeCheck is applicative since every monad is.
-- I do not know why this ain't in the libraries...
instance Applicative TypeCheck where
pure = return
mf <*> ma = mf >>= \ f -> ma >>= \ a -> pure (f a)
-}
{- NOT NEEDED
-- | Dotted constructors (the top one in the pattern).
type Dots = [(Dotted,Pattern)]
emptyDots = []
class LensDots a where
getDots :: a -> Dots
setDots :: Dots -> a -> a
setDots = mapDots . const
mapDots :: (Dots -> Dots) -> a -> a
mapDots f a = setDots (f (getDots a)) a
instance LensDots TCState where
getDots = dots
setDots d st = st { dots = d }
newDotted :: Pattern -> TypeCheck Dotted
newDotted p = do
d <- mkDotted True
modify $ mapDots $ ((d,p):)
return d
clearDots :: TypeCheck ()
clearDots = modify $ setDots emptyDots
openDots :: TypeCheck [Pattern]
openDots = map snd . filter (isDotted . fst) <$> gets dots
-}
-- rewriting rules -----------------------------------------------
data Rewrite = Rewrite { lhs :: Val, rhs :: Val }
type Rewrites = [Rewrite]
emptyRewrites = []
instance Show Rewrite where
show rr = show (lhs rr) ++ " --> " ++ show (rhs rr)
{- renaming ------------------------------------------------------
A renaming maps names to de Bruijn levels (= generic values).
-}
type Ren = Map Name Int
type Env2 = Environ (OneOrTwo Val)
type Context a = Map Int a
type Context2 a = Context (OneOrTwo a)
{- context -------------------------------------------------------
A context maps generic values to their type value.
During type checking, named variables are mapped to
generic values via a renaming. Thus, looking up the type of a
name involves first looking up the generic value, and then its type.
-}
{-
-- data Domain = Domain { typ :: TVal, decor :: Dec }
data Domain = Domain { typ :: TVal, kind :: Class, decor :: Dec }
mapTyp :: (TVal -> TVal) -> Domain -> Domain
mapTyp f dom = dom { typ = f (typ dom) }
mapTypM :: Monad m => (TVal -> m TVal) -> Domain -> m Domain
mapTypM f dom = do
t' <- f (typ dom)
return $ dom { typ = t' }
instance Show Domain where
show item = (if erased (decor item) then brackets else id) (show (typ item))
-}
-- During heterogeneous equality, a variable might have
-- two different types, one on the left and one on the right.
-- We implement this as Two tl tr.
data CxtE a = CxtEntry { domain :: a, upperDec :: UDec }
type CxtEntry = CxtE (OneOrTwo Domain)
type CxtEntry1 = CxtE Domain
data SemCxt = SemCxt
{ len :: Int
, cxt :: Context2 Domain -- fixed part of context
, upperDecs :: Context UDec -- the "should be below" decoration for each var.; this is updated by resurrection
}
{- invariant: length (cxt delta) = length (upperDecs delta) = len
cxt(i) = Two ... iff upperDecs(i) = Two ...
-}
instance Show SemCxt where
show delta =
show $ zip (Map.elems (cxt delta))
(Map.elems (upperDecs delta))
{-
show delta = show $ zip (
zipWith3 (zipWith12 Domain)
-- zipWith (\ entry dec -> fmap ((flip Domain) dec) entry)
(Map.elems (cxt delta))
(Map.elems (kinds delta))
(Map.elems (decs delta))
) (Map.elems (upperDecs delta))
-}
cxtEmpty = SemCxt
{ len = 0
, cxt = Map.empty
-- , kinds = Map.empty
-- , decs = Map.empty
, upperDecs = Map.empty
}
-- push a new type declaration on context
cxtPush' :: OneOrTwo Domain -> SemCxt -> SemCxt
cxtPush' entry delta =
delta { len = k + 1
, cxt = Map.insert k entry (cxt delta)
-- , cxt = Map.insert k (fmap typ entry) (cxt delta)
-- , decs = Map.insert k (fmap decor entry) (decs delta)
, upperDecs = Map.insert k defaultUpperDec (upperDecs delta)
}
where k = len delta
{-
cxtPush' (tv12, dec) delta =
delta { len = k + 1
, cxt = Map.insert k tv12 (cxt delta)
, decs = Map.insert k dec (decs delta) }
where k = len delta
-}
{-
cxtPush :: Dec -> TVal -> SemCxt -> (Int, SemCxt)
cxtPush dec v delta = (len delta, cxtPush' (One (Domain v dec)) delta)
-- cxtPush dec v delta = (len delta, cxtPush' (One v, dec) delta)
-}
cxtPushEntry :: OneOrTwo Domain -> SemCxt -> (Int, SemCxt)
cxtPushEntry ce delta = (len delta, cxtPush' ce delta)
cxtPush :: Domain -> SemCxt -> (Int, SemCxt)
cxtPush dom delta = cxtPushEntry (One dom) delta
-- cxtPush dec v delta = (len delta, cxtPush' (One v, dec) delta)
-- push a variable with a left and a right type
cxtPush2 :: Domain -> Domain -> SemCxt -> (Int, SemCxt)
cxtPush2 doml domr delta = cxtPushEntry (Two doml domr) delta
-- (len delta, cxtPush' (Two doml domr) delta)
{-
-- push a variable with a left and a right type
cxtPush2 :: Dec -> TVal -> TVal -> SemCxt -> (Int, SemCxt)
cxtPush2 dec tvl tvr delta =
(len delta, cxtPush' (Two tvl tvr, dec) delta)
-}
cxtPushGen :: Name -> SemCxt -> (Int, SemCxt)
cxtPushGen x delta = cxtPush bot delta
where bot = error $ "IMPOSSIBLE: name " ++ show x ++ " is not bound to any type"
-- only defined for single bindings
cxtSetType :: Int -> Domain -> SemCxt -> SemCxt
cxtSetType k dom delta =
delta { cxt = Map.insert k (One dom) (cxt delta)
-- upperDecs need not be updated
}
-- | Version of 'Map.lookup' that throws 'TraceError'.
lookupM :: (MonadError TraceError m, Show k, Ord k) => k -> Map k v -> m v
lookupM k m = maybe (throwErrorMsg $ "lookupM: unbound key " ++ show k) return $ Map.lookup k m
cxtLookupGen :: MonadError TraceError m => SemCxt -> Int -> m CxtEntry
cxtLookupGen delta k = do
dom12 <- lookupM k (cxt delta)
udec <- lookupM k (upperDecs delta)
return $ CxtEntry dom12 udec
cxtLookupName :: MonadError TraceError m => SemCxt -> Ren -> Name -> m CxtEntry
cxtLookupName delta ren x = do
i <- lookupM x ren
cxtLookupGen delta i
-- apply decoration, possibly resurrecting (see Pfenning, LICS 2001)
-- and changing polarities (see Abel, MSCS 2008)
cxtApplyDec :: Dec -> SemCxt -> SemCxt
cxtApplyDec dec delta = delta { upperDecs = Map.map (compDec dec) (upperDecs delta) }
-- cxtApplyDec dec delta = delta { decs = Map.map (fmap $ invCompDec dec) (decs delta) }
{- RETIRED, use cxtApplyDec instead
-- clear all "erased" flags (see Pfenning, LICS 2001)
-- UPDATE: resurrection sets "target" status to erased
-- (as opposed to setting "source" status to non-erased)
cxtResurrect :: SemCxt -> SemCxt
cxtResurrect delta = delta { upperDecs = Map.map (\ dec -> dec { erased = True}) (upperDecs delta) }
-- cxtResurrect delta = delta { decs = Map.map (fmap resurrectDec) (decs delta) }
-}
-- manipulating the context ------------------------------------------
{-
-- | Size decrements in bounded quantification do not count for termination
data LamPi
= LamBind -- ^ add a lambda binding to the context
| PiBind -- ^ add a pi binding to the context
-}
class Monad m => MonadCxt m where
-- bind :: Name -> Domain -> Val -> m a -> m a
-- new performs eta-expansion "up" of new gen
-- adding types (Two t1 t2) returns values (Two (Up t1 vi) (Up t2 vi))
newVar :: Name -> OneOrTwo Domain -> (Int -> OneOrTwo Val -> m a) -> m a
newWithGen :: Name -> Domain -> (Int -> Val -> m a) -> m a
newWithGen x d k = newVar x (One d)
(\ i (One v) -> k i v)
new2WithGen:: Name -> (Domain, Domain) -> (Int -> (Val, Val) -> m a) -> m a
new2WithGen x (doml, domr) k = newVar x (Two doml domr)
(\ i (Two vl vr) -> k i (vl, vr))
new :: Name -> Domain -> (Val -> m a) -> m a
new x d cont = newWithGen x d (\ _ -> cont)
new2 :: Name -> (Domain, Domain) -> ((Val, Val) -> m a) -> m a
new2 x d cont = new2WithGen x d (\ _ -> cont)
{-
new2 :: Name -> (TVal, TVal, Dec) -> ((Val, Val) -> m a) -> m a
new2 x d cont = new2WithGen x d (\ _ -> cont)
-}
new' :: Name -> Domain -> m a -> m a
new' x d cont = new x d (\ _ -> cont)
newIrr :: Name -> m a -> m a -- only add binding x = VIrr to env
addName :: Name -> (Val -> m a) -> m a
{- RETIRED
addTypeSigs :: [TySig TVal] -> m a -> m a
addTypeSigs [] k = k
addTypeSigs (TypeSig n tv : tss) k =
new' n (defaultDomain tv) $ addTypeSigs tss k
-}
addKindedTypeSigs :: [Kinded (TySig TVal)] -> m a -> m a
addKindedTypeSigs [] k = k
addKindedTypeSigs (Kinded ki (TypeSig n tv) : ktss) k =
new' n (Domain tv ki defaultDec) $ addKindedTypeSigs ktss k
-- addName x = new x dontCare
setType :: Int -> Domain -> m a -> m a
setTypeOfName :: Name -> Domain -> m a -> m a
genOfName :: Name -> m Int
nameOfGen :: Int -> m Name
-- nameTaken :: Name -> m Bool
uniqueName :: Name -> Int -> m Name
uniqueName x _ = return x -- $ freshen x -- TODO! now freshen causes problems in extraction
{-
uniqueName x k = ifM (nameTaken x) (return $ show x ++ "~" ++ show k) (return x)
-}
lookupGen :: Int -> m CxtEntry
lookupGenType2 :: Int -> m (TVal, TVal)
lookupGenType2 i = do
entry <- lookupGen i
case domain entry of
One d1 -> return (typ d1, typ d1)
Two d1 d2 -> return (typ d1, typ d2)
lookupName :: Name -> m CxtEntry
lookupName1 :: Name -> m CxtEntry1
lookupName1 x = do
e <- lookupName x
return $ CxtEntry (fromOne (domain e)) (upperDec e)
getContextTele :: m TeleVal -- return context as telescope of type values
getLen :: m Int -- return length of the context
getEnv :: m Env -- return current environment
getRen :: m Ren -- return current renaming
applyDec :: Dec -> m a -> m a -- resurrect/adjust polarities
resurrect :: m a -> m a -- resurrect all erased variables in context
resurrect = applyDec irrelevantDec
addRewrite :: Rewrite -> [Val] -> ([Val] -> m a) -> m a
addPattern :: TVal -> Pattern -> Env -> (TVal -> Val -> Env -> m a) -> m a -- step under pat
addPatterns:: TVal -> [Pattern] -> Env -> (TVal -> [Val] -> Env -> m a) -> m a
addSizeRel :: Int -> Int -> Int -> m a -> m a
addBelowInfty :: Int -> m a -> m a
addBoundHyp :: Bound Val -> m a -> m a
isBelowInfty :: Int -> m Bool
sizeVarBelow :: Int -> Int -> m (Maybe Int)
-- getSizeDiff :: Int -> Int -> m (Maybe Int)
getMinSize :: Int -> m (Maybe Int)
getSizeVarsInScope :: m [Name]
checkingCon :: Bool -> m a -> m a
checkingDom :: m a -> m a -- check domain A of Pi x:A.B (takes care of polarities)
setCo :: Co -> m a -> m a -- entering a recursive or corecursive function?
installFuns :: Co -> [Kinded Fun] -> m a -> m a
setMeasure :: Measure Val -> m a -> m a
activateFuns :: m a -> m a -- create instance of mutually recursive functions bounded by measure
goImpredicative :: m a -> m a
checkingMutual :: Maybe DefId -> m a -> m a
dontCare = error "Internal error: tried to retrieve unassigned type of variable"
instance MonadCxt TypeCheck where
newIrr x = local (\ ce -> ce { environ = update (environ ce) x (One VIrr) })
-- UPDATE to 2?
addName x f = enter ("new " ++ show x ++ " : _") $ do
cxtenv <- ask
let (k, delta) = cxtPushGen x (context cxtenv)
let v = VGen k
let rho = update (environ cxtenv) x (One v)
x' <- uniqueName x k
local (\ cxt -> cxt { context = delta
, renaming = Map.insert x k (renaming cxtenv)
, naming = Map.insert k x' (naming cxt)
, environ = rho }) (f v)
newVar x dom12@(One (Domain (VBelow ltle v) ki dec)) f = do
enter ("new " ++ show x ++ " " ++ show ltle ++ " " ++ show v) $ do
cxtenv <- ask
let (k, delta) = cxtPushEntry (One (Domain vSize kSize dec)) (context cxtenv)
let xv = VGen k
let v12 = One xv
let rho = update (environ cxtenv) x v12
let beta = Bound ltle (Measure [xv]) (Measure [v])
x' <- uniqueName x k
local (\ cxt -> cxt { context = delta
, renaming = Map.insert x k (renaming cxtenv)
, naming = Map.insert k x' (naming cxtenv)
, environ = rho }) $
addBoundHyp beta $ (f k v12)
newVar x dom12 f = do
let tv12 = fmap typ dom12
enter ("new " ++ show x ++ " : " ++ show tv12) $ do
cxtenv <- ask
let (k, delta) = cxtPushEntry dom12 (context cxtenv)
v12 <- Traversable.mapM (up False (VGen k)) tv12
let rho = update (environ cxtenv) x v12
x' <- uniqueName x k
local (\ cxt -> cxt { context = delta
, renaming = Map.insert x k (renaming cxtenv)
, naming = Map.insert k x' (naming cxtenv)
, environ = rho }) (f k v12)
{-
newVar x (tv12, dec) f = enter ("new " ++ x ++ " : " ++ show tv12) $ do
cxtenv <- ask
let (k, delta) = cxtPushEntry (tv12, dec) (context cxtenv)
v12 <- Traversable.mapM (up (VGen k)) tv12
let rho = update (environ cxtenv) x v12
local (\ cxt -> cxt { context = delta
, renaming = Map.insert x k (renaming cxtenv)
, environ = rho }) (f k v12)
-}
setType k dom =
local (\ ce -> ce { context = cxtSetType k dom (context ce) })
setTypeOfName x dom cont = do
ce <- ask
let Just k = Map.lookup x (renaming ce)
setType k dom cont
genOfName x = do
ce <- ask
case Map.lookup x (renaming ce) of
Nothing -> throwErrorMsg $ "internal error: variable not bound: " ++ show x
Just k -> return k
nameOfGen k = do
ce <- ask
case Map.lookup k (naming ce) of
Nothing -> return $ fresh $ "error_unnamed_gen" ++ show k
-- throwErrorMsg $ "internal error: no name for variable " ++ show k
Just x -> return x
{-
nameTaken "" = return True
nameTaken x = do
ce <- ask
st <- get
return (Map.member x (renaming ce) || Map.member x (signature st))
-}
lookupGen k = do
ce <- ask
cxtLookupGen (context ce) k
lookupName x = do
ce <- ask
cxtLookupName (context ce) (renaming ce) x
-- does not work with shadowing!
getContextTele = do
ce <- ask
let cxt = context ce
let ren = renaming ce
let env = envMap $ environ ce
let mkTBind (x,_) = (TBind x .fromOne . domain) <$> cxtLookupName cxt ren x
mapM mkTBind env
getLen = do
ce <- ask
return $ len (context ce)
getRen = do
ce <- ask
return $ renaming ce
-- since we only use getEnv during type checking, no case for Two
-- (during equality/subtype checking, we have values)
getEnv = do
ce <- ask
let (Environ rho mmeas) = environ ce
return $ Environ (map (\ (x, One v) -> (x, v)) rho) mmeas
applyDec dec = local (\ ce -> ce { context = cxtApplyDec dec (context ce) })
-- applyDec dec = local (\ ce -> ce { upperDecs = Map.map (compDec dec) (upperDecs ce) })
-- resurrection sets "target" status to erased
-- (as opposed to setting "source" status to non-erased)
{-
resurrect = local (\ ce -> ce { upperDecs =
Map.map (\ dec -> dec { erased = True }) (upperDecs ce) })
-}
{-
resurrect = local (\ ce -> ce { context = cxtResurrect (context ce) })
-}
-- PROBABLY TOO INEFFICIENT
addRewrite rew vs cont = traceRew ("adding rewrite " ++ show rew) $
-- add rewriting rule
local (\ cxt -> cxt { rewrites = rew : (rewrites cxt) }) $ do
ce <- ask
-- normalize all types in context
traceRewM "normalizing types in context"
cx' <- mapMapM (Traversable.mapM (Traversable.mapM reval)) (cxt (context ce)) -- LOOP!
-- normalize environment
traceRewM "normalizing environment"
let Environ rho mmeas = environ ce
rho' <- mapM (\ (x,v12) -> Traversable.mapM reval v12 >>= \ v12' -> return (x, v12')) rho
let en' = Environ rho' mmeas -- no need to rewrite in measure since only size expressions
-- normalize given values
vs' <- mapM reval vs
-- continue in updated context
local (\ ce -> ce { context = (context ce) { cxt = cx' }
, environ = en' }) $ cont vs'
-- addPattern :: TVal -> Pattern -> (TVal -> Val -> Env -> m a) -> m a
addPattern tv@(VQuant Pi x dom fv) p rho cont =
case p of
VarP y -> underAbs y dom fv $ \ _ xv bv -> do
cont bv xv (update rho y xv)
SizeP e y -> underAbs y dom fv $ \ j xv bv -> do
ve <- whnf' e
addBoundHyp (Bound Lt (Measure [xv]) (Measure [ve])) $
cont bv xv (update rho y xv)
{-
SizeP z y -> newWithGen y dom $ \ j xv -> do
bv <- whnf (update env x xv) b
VGen k <- whnf' (Var z)
addSizeRel j 1 k $
cont bv xv (update rho y xv)
-}
ConP pi n pl -> do
sige <- lookupSymbQ n
vc <- conLType n (typ dom)
addPatterns vc pl rho $ \ vc' vpl rho -> do -- apply dom to pl?
pv0 <- mkConVal notDotted (coPat pi) n vpl vc
pv <- up False pv0 (typ dom)
vb <- app fv pv
cont vb pv rho
{-
ConP pi n pl -> do
sige <- lookupSymb n
let vc = symbTyp sige
addPatterns vc pl rho $ \ vc' vpl rho -> do -- apply dom to pl?
pv0 <- foldM app (vCon (coPat pi) n) vpl
pv <- up False pv0 (typ dom)
vb <- whnf (update env x pv) b
cont vb pv rho
-}
SuccP p2 -> do
addPattern (vSize `arrow` vSize) p2 rho $ \ _ vp2 rho -> do
let pv = succSize vp2
vb <- app fv pv
cont vb pv rho
ErasedP p -> addPattern tv p rho cont
-- for dot patterns, we have to do something smart, because they might
-- contain identifiers which are not yet in scope, only after adding
-- other patterns
-- the following trivial solution only works for trivial dot patterns, i.e.,
-- such that do not use yet undeclared identifiers
DotP e -> do
v <- whnf rho e
vb <- app fv v
cont vb v rho -- [(x,v)]
addPatterns tv [] rho cont = cont tv [] rho
addPatterns tv (p:ps) rho cont =
addPattern tv p rho $ \ tv' v env ->
addPatterns tv' ps env $ \ tv'' vs env' ->
cont tv'' (v:vs) env' -- (env' ++ env)
addSizeRel son dist father k = do
let s = "v" ++ show son ++ " + " ++ show dist ++ " <= v" ++ show father
enter -- enterTrace
("adding size rel. " ++ s) $ do
let modBI belowInfty = if father `elem` belowInfty || dist > 0 then son : belowInfty else belowInfty
whenM (asks consistencyCheck `andLazy` do
TSO.increasesHeight son (dist, father) <$> asks sizeRels) $ do
recoverFail $ "cannot add hypothesis " ++ s ++ " because it is not satisfyable under all possible valuations of the current hypotheses"
-- if the new son is an ancestor of the father, we are cyclic
whenJustM (TSO.isAncestor father son <$> asks sizeRels) $ \ n -> -- n steps from father up to son
when (dist > - n) $ -- still ok if dist == n == 0, otherwise fail
recoverFail$ "cannot add hypothesis " ++ s ++ " because it makes the set of hyptheses unsatisfiable"
local (\ cxt -> cxt
{ sizeRels = TSO.insert son (dist, father) (sizeRels cxt)
, belowInfty = modBI (belowInfty cxt)
}) k
addBelowInfty i = local $ \ cxt -> cxt { belowInfty = i : belowInfty cxt }
addBoundHyp beta@(Bound ltle (Measure mu) (Measure mu')) cont =
case (ltle, mu, mu') of
(Le, _, [VInfty]) -> cont
-- (Lt, _, [VInfty]) -> failure -- handle j < #
(ltle, [v], [v']) -> loop (if ltle==Lt then 1 else 0) v v'
_ -> failure
where failure = do
-- recoverFail $ "adding hypothetical constraint " ++ show beta ++ " not supported"
assertDoc' Warning False (text "hypothetical constraint" <+> prettyTCM beta <+> text "ignored")
cont
loop n (VGen i) VInfty = addBelowInfty i cont
loop n (VGen i) (VGen j) | n >= 0 = addSizeRel i n j cont
| otherwise = addIrregularBound i j (-n) cont
loop n (VSucc v) v' = loop (n + 1) v v'
loop n v (VSucc v') = loop (n - 1) v v'
loop _ _ _ = failure
addIrregularBound i j n = local (\ ce -> ce { bounds = beta : bounds ce }) where
v' = iterate VSucc (VGen j) !! n
beta = Bound Le (Measure [VGen i]) (Measure [v'])
isBelowInfty i = (i `elem`) <$> asks belowInfty
{-
isBelowInfty i = do
belowInfty <- asks belowInfty
if (i `elem` belowInfty) then return True else do
tso <- asks sizeRels
loop $ parents i tso where
loop [] = return False
loop [(_,j)] = return $ j `elem` belowInfty
loop (x:xs) = loop xs
-}
sizeVarBelow son ancestor = do
cxt <- ask
return $ TSO.isAncestor son ancestor (sizeRels cxt)
{-
getSizeDiff son ancestor = do
cxt <- ask
return $ TSO.diff son ancestor (sizeRels cxt)
-}
getMinSize parent = do
cxt <- ask
return $ TSO.height parent (sizeRels cxt)
getSizeVarsInScope = do
TCContext { context = delta, naming = nam } <- ask
-- get all the size variables with positive or mixed polarity
let fSize (i, tv12) =
case tv12 of
One dom -> isVSize $ typ dom
_ -> -- trace ("not a size variable " ++ show i ++ " : " ++ show tv12) $
False
-- create a list of key (gen) and Domain pairs for the size variables
let idl = filter fSize $ Map.toAscList (cxt delta)
let udecs = upperDecs delta
let fPos (i, One dom) =
case fromPProd (polarity (Maybe.fromJust (Map.lookup i udecs))) of
Just p -> leqPol (polarity (decor dom)) p
Nothing -> False
let fName (i, _) = Maybe.fromJust $ Map.lookup i nam
return $ map fName $ filter fPos idl
checkingCon b = local (\ cxt -> cxt { checkingConType = b})
{-
checkingDom = local $ \ cxt ->
if checkingConType cxt then cxt
else cxt { context = cxtApplyDec (Dec False Neg) (context cxt) }
-}
-- check domain A of (x : A) -> B
checkingDom k = do
b <- asks checkingConType
if b then k else applyDec (Dec Neg) k
setCo co = local (\ cxt -> cxt { mutualCo = co })
-- install functions for checking function clauses
-- ==> use internal names
installFuns co kfuns k = do
let funt = foldl (\ m fun@(Kinded _ (Fun (TypeSig n _) n' _ _)) -> Map.insert n fun m)
Map.empty
kfuns
local (\ cxt -> cxt { mutualCo = co, funsTemplate = funt }) k
setMeasure mu k = do
rho0 <- getEnv
let rho = rho0 { envBound = Just mu }
local (\ cxt -> cxt
{ environ = (environ cxt) { envBound = Just mu }
}) k
activateFuns k = do
rho <- getEnv
case (envBound rho) of
Nothing -> k
Just mu ->
local (\ cxt -> cxt
{ mutualFuns =
Map.map (boundFun rho (mutualCo cxt)) (funsTemplate cxt)
}) k
where boundFun :: Env -> Co -> Kinded Fun -> SigDef
boundFun rho co (Kinded ki (Fun (TypeSig n t) n' ar cls)) =
FunSig co (VClos rho t) ki ar cls False undefined
{-
activateFuns mu k = do
rho0 <- getEnv
let rho = rho0 { envBound = Just mu }
local (\ cxt -> cxt
{ environ = (environ cxt) { envBound = Just mu }
, mutualFuns =
Map.map (boundFun rho (mutualCo cxt)) (funsTemplate cxt)
}) k
where boundFun :: Env -> Co -> Fun -> SigDef
boundFun rho co (TypeSig n t, (ar, cls)) =
FunSig co (VClos rho t) ar cls False
-}
goImpredicative = local (\ cxt -> cxt { impredicative = True })
checkingMutual mn = local (\ cxt -> cxt { checkingMutualName = mn })
-- | Go into the codomain of a Pi-type or open an abstraction.
underAbs :: Name -> Domain -> FVal -> (Int -> Val -> Val -> TypeCheck a) -> TypeCheck a
underAbs x dom fv cont = newWithGen x dom $ \ i xv -> cont i xv =<< app fv xv
-- | Do not check consistency preservation of context.
underAbs_ :: Name -> Domain -> FVal -> (Int -> Val -> Val -> TypeCheck a) -> TypeCheck a
underAbs_ x dom fv cont = noConsistencyChecking $ underAbs x dom fv cont
noConsistencyChecking = local $ \ cxt -> cxt { consistencyCheck = False }
-- | No eta, no hypotheses. First returned val is a @VGen i@.
underAbs' :: Name -> FVal -> (Val -> Val -> TypeCheck a) -> TypeCheck a
underAbs' x fv cont = addName x $ \ xv -> cont xv =<< app fv xv
-- addBind :: MonadTCM m => TBind -> m a -> m a
addBind :: TBind -> TypeCheck a -> TypeCheck a
addBind (TBind x dom) cont = do
dom' <- (Traversable.mapM whnf' dom)
new' x dom' cont
addBinds :: Telescope -> TypeCheck a -> TypeCheck a
addBinds tel k0 = foldr addBind k0 $ telescope tel
-- introduce patterns into context and environment -------------------
-- DOES NOT ETA-EXPAND VARIABLES!! -----------------------------------
introPatterns :: [Pattern] -> TVal -> ([(Pattern,Val)] -> TVal -> TypeCheck a) -> TypeCheck a
introPatterns ps tv cont = -- Problem: NO ETA EXPANSION!
introPatVars ps $ do -- first bind pattern variables
vs <- mapM (whnf' . patternToExpr) ps -- now we can evaluate patterns
let pvs = zip ps vs
introPatTypes pvs tv (cont pvs) -- now we can assign types to pvars
-- introduce variables bound in pattern into the environment
-- extend delta by generic values but do not introduce their types
-- this is to deal with dot patterns
introPatVar :: Pattern -> TypeCheck a -> TypeCheck a
introPatVar p cont =
case p of
VarP n -> addName n $ \ _ -> cont
SizeP m n -> addName n $ \ _ -> cont
ConP co n pl -> introPatVars pl cont
PairP p1 p2 -> introPatVars [p1,p2] cont
SuccP p -> introPatVar p cont
ProjP{} -> cont
DotP e -> cont
AbsurdP -> cont
ErasedP p -> introPatVar p cont
introPatVars :: [Pattern] -> TypeCheck a -> TypeCheck a
introPatVars [] cont = cont
introPatVars (p:ps) cont = introPatVar p $ introPatVars ps $ cont
-- if the bindings name->gen are already in the environment
-- we can now bind the gen to their types
introPatType :: (Pattern,Val) -> TVal -> (TVal -> TypeCheck a) -> TypeCheck a
introPatType (p,v) tv cont = do
case tv of
VGuard beta bv -> addBoundHyp beta $ introPatType (p,v) bv cont
VApp (VDef (DefId DatK d)) vl ->
case p of
ProjP n -> cont =<< projectType tv n VIrr -- no record value here
_ -> throwErrorMsg $ "introPatType: internal error, expected projection pattern, found " ++ show p ++ " at type " ++ show tv
VQuant Pi x dom fv -> do
v <- whnfClos v
matchPatType (p,v) dom . cont =<< app fv v
_ -> throwErrorMsg $ "introPatType: internal error, expected Pi-type, found " ++ show tv
introPatTypes :: [(Pattern,Val)] -> TVal -> (TVal -> TypeCheck a) -> TypeCheck a
introPatTypes pvs tv f = do
case pvs of
[] -> f tv
(pv:pvs') -> introPatType pv tv $ \ tv' -> introPatTypes pvs' tv' f
matchPatType :: (Pattern, Val) -> Domain -> TypeCheck a -> TypeCheck a
matchPatType (p,v) dom cont =
case (p,v) of
-- erasure does not matter!
(VarP y, VGen k) -> setType k dom $ cont
(SizeP z y, VGen k) -> setType k dom $ cont
(ConP co n [], _) -> cont
(ConP co n pl, VApp (VDef (DefId ConK{} _)) vl) -> do
{-
sige <- lookupSymb n
let vc = symbTyp sige
-}
vc <- conType n =<< force (typ dom)
introPatTypes (zip pl vl) vc $ \ _ -> cont
(SuccP p2, VSucc v2) -> matchPatType (p2, v2) (defaultDomain vSize) $ cont
(PairP p1 p2, VPair v1 v2) -> do
av <- force (typ dom)
case av of
VQuant Sigma x dom1@(Domain av1 ki dec) fv -> do
matchPatType (p1,v1) dom1 $ do
bv <- app fv v1
matchPatType (p2,v2) (Domain bv ki dec) cont
_ -> throwErrorMsg $ "matchPatType: IMPOSSIBLE " ++ show p ++ " : " ++ show dom
(DotP e, _) -> cont
(AbsurdP, _) -> cont
(ErasedP p,_) -> matchPatType (p,v) dom cont
_ -> throwErrorMsg $ "matchPatType: IMPOSSIBLE " ++ show (p,v)
-- Signature -----------------------------------------------------
-- input to and output of the type-checker
type Signature = Map QName SigDef
-- a signature entry is either
-- * a fun/cofun,
-- * a defined constant,
-- * a constructor, or
-- * a data type id with its kind
-- they share "symbTyp", the type signature of the definition
data SigDef
= FunSig { isCo :: Co
, symbTyp :: TVal
, symbolKind :: Kind
, arity :: Arity
, clauses :: [Clause]
, isTypeChecked :: Bool
, extrTyp :: Expr -- ^ Fomega type.
}
| LetSig { symbTyp :: TVal
, symbolKind :: Kind
, definingVal :: Val
-- , definingExpr :: Expr
, extrTyp :: Expr -- ^ Fomega type.
}
| PatSig { patVars :: [Name]
, definingPat :: Pattern
, definingVal :: Val
}
| ConSig { conPars :: ConPars
-- ^ Parameter patterns and no. of variable they bind.
-- @Nothing@ if old-style parameters.
, lhsTyp :: LHSType
-- ^ LHS type of constructor for pattern matching, e.g.
-- rhs @cons : [A : Set] [i : Size] -> A -> List A i -> List A $i@
-- lhs @cons : [A : Set] [i : Size] [j < i] -> A -> List A j -> List A i@
-- @Name@ is the name of the size parameter.
, recOccs :: [Bool]
-- ^ @True@ if argument contains rec.occs.of the (co)data type?
, symbTyp :: TVal -- ^ (RHS) type, includs parameter tel.
, dataName :: Name -- ^ Its datatype.
, dataPars :: Int -- ^ No. of parameters of its datatype.
, extrTyp :: Expr -- ^ Fomega type.
}
| DataSig { numPars :: Int
, positivity :: [Pol]
, isSized :: Sized
, isCo :: Co
, symbTyp :: TVal
, symbolKind :: Kind
-- the following information is only needed for eta-expansion
-- hence it is only provided for suitable ind.fams.
, constructors :: [ConstructorInfo]
, etaExpand :: Bool -- non-overlapping pattern inductive family
-- with at least one eta-expandable constructor
, isTuple :: Bool -- each constructor is irrefutable
-- must be (NEW: non-overlapping) pattern inductive family
-- qualifies for target of corecursive fun
-- NO LONGER: exactly one constructor
-- NOW: at least one constructor
-- can be recursive
, extrTyp :: Expr -- Fomega kind
{-
, destructors :: Maybe [Name] -- Nothing if not a record
, isFamily :: Bool
-}
} -- # parameters, positivity of parameters , sized , co , type
deriving (Show)
-- | Parameter patterns and no. of variables they bind.
type ConPars = Maybe ([Name], [Pattern])
-- | LHS type plus name of size index.
type LHSType = Maybe (Name, TVal)
isEmptyData :: QName -> TypeCheck Bool
isEmptyData n = do
sig <- lookupSymbQ n
case sig of
DataSig { constructors } -> return $ null constructors
_ -> throwErrorMsg $ "internal error: isEmptyData " ++ show n ++ ": name of data type expected"
isUnitData :: QName -> TypeCheck Bool
isUnitData n = do
sig <- lookupSymbQ n
case sig of
DataSig { constructors = [c], isTuple } -> return $
isTuple && null (cFields c) && cPatFam c == (LinearPatterns, [])
DataSig { constructors } -> return False
_ -> throwErrorMsg $ "internal error: isUnitData " ++ show n ++ ": name of data type expected"
undefinedFType :: QName -> Expr
undefinedFType n = Irr
-- undefinedFType n = error $ "no extracted type for " ++ show n
symbKind :: SigDef -> Kind
symbKind ConSig{} = kTerm -- constructors are always terms
symbKind d = symbolKind d -- else: lookup
{- Data types can be big!!
symbKind DataSig{} = kType -- data types are never universes
-}
emptySig = Map.empty
-- Handling constructor types ------------------------------------------
data DataView
= Data Name [Clos]
| NoData
-- | Check if type @tv@ is a datatype @D vs@.
dataView :: TVal -> TypeCheck DataView
dataView tv = do
tv <- force tv
case tv of
{- 2012-01-31 EVIL, LEADS TO UNBOUND VARS:
VQuant Pi x dom env b -> do
new x dom $ \ xv -> dataView =<< whnf (update env x xv) b
-}
VApp (VDef (DefId DatK n)) vs -> return $ Data (unqual n) vs
VSing v dv -> dataView =<< whnfClos dv
_ -> return $ NoData
-- | Disambiguate possibly overloaded constructor @c@ at given type @tv@.
disambigCon :: QName -> TVal -> TypeCheck QName
disambigCon c tv =
case c of
Qual{} -> return c
QName n -> do
dv <- dataView tv
case dv of
Data d _ -> return $ Qual d n
_ -> throwErrorMsg $ "cannot resolve constructor " ++ show n
-- | @conType c tv@ returns the type of constructor @c@ at datatype @tv@
-- with parameters instantiated.
conType :: QName -> TVal -> TypeCheck TVal
conType c tv = do
c <- disambigCon c tv
ConSig { conPars, symbTyp, dataName, dataPars } <- lookupSymbQ c
instConType c conPars symbTyp dataName dataPars tv
-- | Get LHS type of constructor.
--
-- Constructors or sized data types internally have a lhs type
-- that differs from its rhs type. E.g.,
-- rhs @suc : [i : Size] -> Nat i -> Nat $i@
-- lhs @suc : [i : Size] [j < i] -> Nat j -> Nat i@.
-- In the lhs type, @i@ turns into an additional parameter.
conLType :: QName -> TVal -> TypeCheck TVal
conLType c tv = do
c <- disambigCon c tv
ConSig { conPars, lhsTyp, symbTyp, dataName, dataPars } <- lookupSymbQ c
case lhsTyp of
Nothing -> instConType c conPars symbTyp dataName dataPars tv
Just (x, lTyp) -> instConType c (fmap (inc x) conPars) lTyp dataName (dataPars+1) tv
where inc x (xs, ps) = (xs ++ [x], ps ++ [VarP x])
-- | Instantiate type of constructor to parameters obtained from
-- the data type.
--
-- @instConType c n symbTyp dataName tv@
-- instantiates type @symbTyp@ of constructor @c@ with first @n@ arguments
-- that @dataName@ is applied to in @tv@.
-- @@
-- instConType c n ((x1:A1..xn:An) -> B) d (d v1..vn ws) = B[vs/xs]
-- @@
instConType :: QName -> ConPars -> TVal -> Name -> Int -> TVal -> TypeCheck TVal
instConType c conPars symbTyp dataName dataPars tv =
instConLType' c conPars symbTyp Nothing (Just dataName) dataPars tv
{-
instConType c numPars symbTyp dataName tv = do
dv <- dataView tv
case dv of
NoData -> failDoc (text ("conType " ++ show c ++ ": expected")
<+> prettyTCM tv <+> text "to be a data type")
Data d vs -> do
unless (d == dataName) $ throwErrorMsg $ "expected constructor of datatype " ++ show d ++ ", but found one of datatype " ++ show dataName
let (pars, inds) = splitAt numPars vs
unless (length pars == numPars) $
failDoc (text ("conType " ++ show c ++ ": expected")
<+> prettyTCM tv
<+> text ("to be a data type applied to all of its " ++
show numPars ++ " parameters"))
piApps symbTyp pars
-}
-- | Get correct lhs type for constructor pattern.
--
-- @instConLType c numPars symbTyp Nothing isFlex tv@ behaves like
-- @instConLType c numPars symbType _ tv@.
--
-- But if the data types is sized and the constructor has a lhs type,
-- @instConLType c numPars symbTyp (Just ltv) isFlex tv@
-- uses the lhs type @ltv@ unless the variable instantiated for
-- the size argument is flexible (because then it wants to be
-- unified with the successor pattern of the rhs type.
instConLType :: QName -> ConPars -> TVal -> LHSType -> (Val -> Bool) -> Int -> TVal -> TypeCheck TVal
instConLType c conPars rhsTyp lhsTyp isFlex dataPars dataTyp =
instConLType' c conPars rhsTyp (fmap (,isFlex) lhsTyp) Nothing dataPars dataTyp
-- | The common pattern behind @instConType@ and @instConLType@.
instConLType' :: QName -> ConPars -> TVal -> Maybe ((Name, TVal), Val -> Bool) -> Maybe Name -> Int -> TVal -> TypeCheck TVal
instConLType' c conPars symbTyp isSized md dataPars tv =
enter ("instConLType'") $ do
let failure = failDoc (text ("conType " ++ show c ++ ": expected")
<+> prettyTCM tv
<+> text ("to be a data type applied to all of its " ++
show dataPars ++ " parameters"))
dv <- dataView tv
case dv of
NoData -> failDoc (text ("conType " ++ show c ++ ": expected")
<+> prettyTCM tv <+> text "to be a data type")
Data d vs -> do
whenJust md $ \ d' ->
unless (d == d') $ throwErrorMsg $ "expected constructor of datatype " ++ show d ++ ", but found one of datatype " ++ show d'
-- whenJust conPars $ throwErrorMsg $ "NYI: constructor with pattern parameters"
let (pars, inds) = splitAt dataPars vs
unless (length pars == dataPars) failure
case (isSized, inds) of
(Just _, []) -> failure
-- if size index not flexible, use lhs type
(Just ((x,ltv), isFlex), sizeInd:_) | not (isFlex sizeInd) ->
continue d [x] ltv (pars ++ [sizeInd])
-- otherwise, use rhs type
_ -> continue d [] symbTyp pars
where
continue d ys tv pars = case conPars of
Nothing -> piApps tv pars
Just (xs, ps) -> do
let failure = failDoc $ sep
[ text "instConType:"
, text "cannot match parameters" <+> prettyList (map prettyTCM pars)
, text "against patterns" <+> prettyList (map prettyTCM ps)
, text "when instantiating type" <+> prettyTCM tv
, text ("of constructor " ++ show c)
]
-- clear dots here:
mst <- nonLinMatchList' True True (emptyEnv, []) ps pars =<< lookupSymbTyp d
case mst of
Nothing -> failure
Just (Environ{ envMap = env0 }, psub) -> do
let env = env0 ++ [ (x, VGen i) | (i, VarP x) <- psub ]
-- if length env /= length xs then failure else do
vs <- forM (xs ++ ys) $ \ x -> maybe failure return $ lookup x env
piApps tv vs
{-
menv <- matchList emptyEnv ps pars
case menv of
Nothing -> failure
Just Environ{ envMap = env } -> if length env /= length xs then failure else do
vs <- forM (xs ++ ys) $ \ x -> maybe failure return $ lookup x env
piApps tv vs
-}
{-
case isSized of
Nothing -> piApps symbTyp pars
Just ltv -> do
when (null inds) failure
let sizeInd = head inds
if isFlex sizeInd then piApps symbTyp pars else piApps ltv (pars ++ [sizeInd])
-}
-- Signature specification -------------------------------------------
class MonadCxt m => MonadSig m where
lookupSymbTypQ :: QName -> m TVal
lookupSymbQ :: QName -> m SigDef
addSigQ :: QName -> SigDef -> m ()
modifySigQ :: QName -> (SigDef -> SigDef) -> m ()
setExtrTypQ :: QName -> Expr -> m ()
lookupSymbTyp :: Name -> m TVal
lookupSymbTyp = lookupSymbTypQ . QName
lookupSymb :: Name -> m SigDef
lookupSymb = lookupSymbQ . QName
addSig :: Name -> SigDef -> m ()
addSig = addSigQ . QName
modifySig :: Name -> (SigDef -> SigDef) -> m ()
modifySig = modifySigQ . QName
setExtrTyp :: Name -> Expr -> m ()
setExtrTyp = setExtrTypQ . QName
-- Signature implementation ------------------------------------------
instance MonadSig TypeCheck where
-- first in context, then in signature
-- lookupSymbTyp :: Name -> TypeCheck TVal
lookupSymbTyp n = do
mdom <- errorToMaybe $ lookupName1 n
case mdom of
Just (CxtEntry dom udec) -> return (typ dom)
Nothing -> symbTyp <$> lookupSymb n
lookupSymbTypQ (QName n) = lookupSymbTyp n
lookupSymbTypQ n@Qual{} = symbTyp <$> lookupSymbQ n
-- lookupSymb :: Name -> TypeCheck SigDef
lookupSymb n = do
cxt <- ask
case Map.lookup n (mutualFuns cxt) of
Just k -> return $ k
Nothing -> lookupSymbInSig (QName n)
lookupSymbQ (QName n) = lookupSymb n
lookupSymbQ n@Qual{} = lookupSymbInSig n
-- addSig :: Name -> SigDef -> TypeCheck ()
addSigQ n def = traceSig ("addSig: " ++ show n ++ " is bound to " ++ show def) $do
st <- get
put $ st { signature = Map.insert n def $ signature st }
-- modifySig :: Name -> (SigDef -> SigDef) -> TypeCheck ()
modifySigQ n f = do
st <- get
put $ st { signature = Map.adjust f n $ signature st }
-- setExtrTyp :: Name -> Expr -> TypeCheck ()
setExtrTypQ n t = modifySigQ n (\ d -> d { extrTyp = t })
lookupSymbInSig :: QName -> TypeCheck SigDef
lookupSymbInSig n = lookupSig n =<< gets signature
where
-- lookupSig :: Name -> Signature -> TypeCheck SigDef
lookupSig n sig =
case (Map.lookup n sig) of
Nothing -> throwErrorMsg $ "identifier " ++ show n ++ " not in signature " ++ show (Map.keys sig)
Just k -> return k
-- more on the type checking monad -------------------------------
initSt :: TCState
initSt = TCState emptySig emptyMetaVars emptyConstraints emptyPosGraph -- emptyDots
initWithSig :: Signature -> TCState
initWithSig sig = initSt { signature = sig }
-- Meta-variable and constraint handling specification ---------------
class Monad m => MonadMeta m where
resetConstraints :: m ()
mkConstraint :: Val -> Val -> m (Maybe Constraint)
addMeta :: Ren -> MVar -> m ()
addLeq :: Val -> Val -> m ()
addLe :: LtLe -> Val -> Val -> m ()
addLe Le v1 v2 = addLeq v1 v2
addLe Lt v1 v2 = addLeq (succSize v1) v2 -- broken for #
solveConstraints :: m Solution
-- solve constraints and substitute solution into the analyzed expressions
solveAndModify :: [Expr] -> Env -> m [Expr]
solveAndModify es rho = do
sol <- solveConstraints
let es' = map (subst (solToSubst sol rho)) es
resetConstraints
return es'
-- Constraints implementation ----------------------------------------
instance MonadMeta TypeCheck where
--resetConstraints :: TypeCheck ()
resetConstraints = do
st <- get
put $ st { constraints = emptyConstraints }
-- mkConstraint :: Val -> Val -> TypeCheck (Maybe Constraint)
mkConstraint v (VMax vs) = do
bs <- mapM (errorToBool . leqSize' v) vs
if any id bs then return Nothing else
throwErrorMsg $ "cannot handle constraint " ++ show v ++ " <= " ++ show (VMax vs)
mkConstraint w@(VMax vs) v = throwErrorMsg $ "cannot handle constraint " ++ show w ++ " <= " ++ show v
mkConstraint (VMeta i rho n) (VMeta j rho' m) = retret $ arc (Flex i) (m-n) (Flex j)
mkConstraint (VMeta i rho n) VInfty = retret $ arc (Flex i) 0 (Rigid (RConst Infinite))
mkConstraint (VMeta i rho n) v = retret $ arc (Flex i) (m-n) (Rigid (RVar j))
where (j,m) = vGenSuccs v 0
mkConstraint VInfty (VMeta i rho n) = retret $ arc (Rigid (RConst Infinite)) 0 (Flex i)
mkConstraint v (VMeta j rho m) = retret $ arc (Rigid (RVar i)) (m-n) (Flex j)
where (i,n) = vGenSuccs v 0
mkConstraint v1 v2 = throwErrorMsg $ "mkConstraint undefined for " ++ show (v1,v2)
-- addMeta k x adds a metavariable which can refer to VGens < k
-- addMeta :: Ren -> MVar -> TypeCheck ()
addMeta ren i = do
scope <- getSizeVarsInScope
traceMetaM ("addMeta " ++ show i ++ " scope " ++ show scope)
st <- get
put $ st { metaVars = Map.insert i (MetaVar scope Nothing) (metaVars st)
, constraints = NewFlex i (\ k' -> True) -- k' < k)
-- DO NOT ADD constraints of form <= infty !!
-- : arc (Flex i) 0 (Rigid (RConst Infinite))
: constraints st }
-- addLeq :: Val -> Val -> TypeCheck ()
addLeq v1 v2 = traceMeta ("Constraint: " ++ show v1 ++ " <= " ++ show v2) $
do mc <- mkConstraint v1 v2
case mc of
Nothing -> return ()
Just c -> do
st <- get
put $ st { constraints = c : constraints st }
-- solveConstraints :: TypeCheck Solution
solveConstraints = do
cs <- gets constraints
if null cs then return emptySolution
else case solve cs of
Just subst -> traceMeta ("solution" ++ show subst) $
return subst
Nothing -> throwErrorMsg $ "size constraints " ++ show cs ++ " unsolvable"
nameOf :: EnvMap -> Int -> Maybe Name
nameOf [] j = Nothing
nameOf ((x,VGen i):rho) j | i == j = Just x
nameOf (_:rho) j = nameOf rho j
vGenSuccs (VGen k) m = (k,m)
vGenSuccs (VSucc v) m = vGenSuccs v (m+1)
vGenSuccs v m = error $ "vGenSuccs fails on " ++ Util.parens (show v) ++ " " ++ show m
retret = return . return
sizeExprToExpr :: Env -> SizeExpr -> Expr
sizeExprToExpr rho (SizeConst Infinite) = Infty
sizeExprToExpr rho (SizeVar i n) | Just x <- nameOf (envMap rho) i = add (Var x) n
where add e n | n <= 0 = e
| otherwise = add (Succ e) (n-1)
sizeExprToExpr rho e@(SizeVar i n) | Nothing <- nameOf (envMap rho) i = error $ "panic: sizeExprToExpr " ++ Util.parens (show e) ++ ": variable v" ++ show i ++ " not in scope " ++ show (envMap rho)
maxExpr :: [Expr] -> Expr
maxExpr [] = Infty
maxExpr [e] = e
maxExpr l = if Infty `elem` l then Infty else Max l
solToSubst :: Solution -> Env -> Subst
solToSubst sol rho = Map.map (maxExpr . map (sizeExprToExpr rho)) sol
{-
solToSubst :: Solution -> Env -> Subst
solToSubst sol rho = Map.foldWithKey step Map.empty sol
where step k (SizeVar i n) sub | Just x <- nameOf rho i =
Map.insert k (add (Var x) n) sub
step k (SizeConst Infinite) sub = Map.insert k Infty sub
step _ _ sub = sub
add e n | n <= 0 = e
| otherwise = add (Succ e) (n-1)
-}
-- pattern to Value ----------------------------------------------
{- RETIRED
patternToVal :: Pattern -> TypeCheck Val
patternToVal p = do
k <- getLen
return $ fst (p2v k p)
-- turn a pattern into a value
-- dot patterns get variables corresponding to their flexible generic value
p2v :: Int -> Pattern -> (Val,Int)
p2v k p =
case p of
VarP n -> (VGen k,k+1)
ConP co n [] -> (VCon co n,k)
ConP co n pl -> let (vl,k') = ps2vs k pl
in (VApp (VCon co n) vl,k')
SuccP p -> let (v,k') = p2v k p
in (VSucc v,k')
DotP e -> (VGen k,k+1)
ps2vs :: Int -> [Pattern] -> ([Val],Int)
ps2vs k [] = ([],k)
ps2vs k (p:pl) = let (v,k') = p2v k p
(vl,k'') = ps2vs k' pl
in
(v:vl,k'')
-}