{-# OPTIONS_GHC -Wunused-imports #-}
{-# LANGUAGE NondecreasingIndentation #-}
module Agda.TypeChecking.Lock
( isTimeless
, checkLockedVars
, checkEarlierThan
)
where
import Prelude hiding (null)
import qualified Prelude as Prelude
import qualified Data.IntMap as IMap
import qualified Data.Set as Set
import Agda.Syntax.Common
import Agda.Syntax.Internal
import Agda.TypeChecking.Monad
import Agda.TypeChecking.Pretty
import Agda.TypeChecking.Constraints ()
import Agda.TypeChecking.Reduce
import Agda.TypeChecking.Substitute.Class
import Agda.TypeChecking.Free
import qualified Agda.Utils.List1 as List1
import qualified Agda.Utils.VarSet as VarSet
import Agda.Utils.VarSet (VarSet)
import Agda.Utils.Maybe
import Agda.Utils.Monad
import Agda.Utils.Null
import Agda.Utils.Size
checkLockedVars ::
Term
-> Type
-> Arg Term
-> Type
-> TCM ()
checkLockedVars :: Term -> Type'' Term Term -> Arg Term -> Type'' Term Term -> TCM ()
checkLockedVars Term
t Type'' Term Term
ty Arg Term
lk Type'' Term Term
lk_ty = do
lk <- Arg Term -> TCMT IO (Arg Term)
forall a (m :: * -> *).
(InstantiateFull a, MonadReduce m) =>
a -> m a
instantiateFull Arg Term
lk
catchConstraint (CheckLockedVars t ty lk lk_ty) do
reportSDoc "tc.term.lock" 40 $ "Checking locked vars.."
reportSDoc "tc.term.lock" 45 $ nest 2 $ vcat
[ text "t = " <+> prettyTCM t
, text "ty = " <+> prettyTCM ty
, text "lk = " <+> prettyTCM lk
, text "lk_ty = " <+> prettyTCM lk_ty
]
reportSDoc "tc.term.lock" 80 $ nest 2 $ vcat
[ text "t = " <+> pretty t
, text "ty = " <+> pretty ty
, text "lk = " <+> pretty lk
, text "lk_ty = " <+> pretty lk_ty
]
mi <- getLockVar (unArg lk)
caseMaybe mi (typeError (DoesNotMentionTicks t ty lk)) $ \ Int
i -> do
cxt <- TCMT IO (Context' ContextEntry)
forall (m :: * -> *). MonadTCEnv m => m (Context' ContextEntry)
getContext
let fv = (Term, Type'' Term Term) -> VarMap
forall t. Free t => t -> VarMap
freeVarMapIgnoreAnn (Term
t,Type'' Term Term
ty)
let
rigid = VarMap -> VarSet
rigidVars VarMap
fv
termVars = VarMap -> VarSet
allVars VarMap
fv
earlierVars = Int -> Int -> VarSet
VarSet.range Int
i (Context' ContextEntry -> Int
forall a. Sized a => a -> Int
size Context' ContextEntry
cxt)
if termVars `VarSet.isSubsetOf` earlierVars then return () else do
let toCheck = [Int] -> [ContextEntry] -> [(Int, ContextEntry)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] ([ContextEntry] -> [(Int, ContextEntry)])
-> [ContextEntry] -> [(Int, ContextEntry)]
forall a b. (a -> b) -> a -> b
$ (Int -> ContextEntry -> ContextEntry)
-> [Int] -> [ContextEntry] -> [ContextEntry]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> ContextEntry -> ContextEntry
forall a. Subst a => Int -> a -> a
raise [Int
1..] ([ContextEntry] -> [ContextEntry])
-> [ContextEntry] -> [ContextEntry]
forall a b. (a -> b) -> a -> b
$ Int -> Context' ContextEntry -> [ContextEntry]
cxTake Int
i Context' ContextEntry
cxt
checked <- fmap catMaybes . forM toCheck $ \ (Int
j,ContextEntry
ce) -> do
TCMT IO Bool
-> TCMT IO (Maybe Int)
-> TCMT IO (Maybe Int)
-> TCMT IO (Maybe Int)
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (Type'' Term Term -> TCMT IO Bool
isTimeless (ContextEntry -> Type'' Term Term
ctxEntryType ContextEntry
ce))
(Maybe Int -> TCMT IO (Maybe Int)
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Int -> TCMT IO (Maybe Int))
-> Maybe Int -> TCMT IO (Maybe Int)
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int
forall a. a -> Maybe a
Just Int
j)
(Maybe Int -> TCMT IO (Maybe Int)
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Int -> TCMT IO (Maybe Int))
-> Maybe Int -> TCMT IO (Maybe Int)
forall a b. (a -> b) -> a -> b
$ Maybe Int
forall a. Maybe a
Nothing)
let allowedVars = VarSet -> VarSet -> VarSet
VarSet.union VarSet
earlierVars ([Int] -> VarSet
VarSet.fromList [Int]
checked)
if termVars `VarSet.isSubsetOf` allowedVars then return () else do
let
illegalVars = VarSet
rigid VarSet -> VarSet -> VarSet
`VarSet.difference` VarSet
allowedVars
if null illegalVars then
patternViolation alwaysUnblock
else
typeError $ ReferencesFutureVariables t (List1.fromList (VarSet.toAscList illegalVars)) lk i
getLockVar :: Term -> TCMT IO (Maybe Int)
getLockVar :: Term -> TCMT IO (Maybe Int)
getLockVar Term
lk = do
let
fv :: VarMap
fv = Term -> VarMap
forall t. Free t => t -> VarMap
freeVarMapIgnoreAnn Term
lk
flex :: IntMap MetaSet
flex = VarMap -> IntMap MetaSet
flexibleVars VarMap
fv
isLock :: Int -> f Bool
isLock Int
i = (Dom' Term (Type'' Term Term) -> Lock)
-> f (Dom' Term (Type'' Term Term)) -> f Lock
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ArgInfo -> Lock
forall a. LensLock a => a -> Lock
getLock (ArgInfo -> Lock)
-> (Dom' Term (Type'' Term Term) -> ArgInfo)
-> Dom' Term (Type'' Term Term)
-> Lock
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dom' Term (Type'' Term Term) -> ArgInfo
forall t e. Dom' t e -> ArgInfo
domInfo) (Int -> f (Dom' Term (Type'' Term Term))
forall (m :: * -> *).
(MonadDebug m, MonadTCEnv m) =>
Int -> m (Dom' Term (Type'' Term Term))
domOfBV Int
i) f Lock -> (Lock -> Bool) -> f Bool
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
IsLock{} -> Bool
True
IsNotLock{} -> Bool
False
Bool -> TCM () -> TCM ()
forall b (m :: * -> *). (IsBool b, Monad m) => b -> m () -> m ()
unless (IntMap MetaSet -> Bool
forall a. IntMap a -> Bool
IMap.null IntMap MetaSet
flex) (TCM () -> TCM ()) -> TCM () -> TCM ()
forall a b. (a -> b) -> a -> b
$ do
let metas :: Set MetaId
metas = [Set MetaId] -> Set MetaId
forall (f :: * -> *) a. (Foldable f, Ord a) => f (Set a) -> Set a
Set.unions ([Set MetaId] -> Set MetaId) -> [Set MetaId] -> Set MetaId
forall a b. (a -> b) -> a -> b
$ (MetaSet -> Set MetaId) -> [MetaSet] -> [Set MetaId]
forall a b. (a -> b) -> [a] -> [b]
map ((MetaId -> Set MetaId -> Set MetaId)
-> Set MetaId -> MetaSet -> Set MetaId
forall a. (MetaId -> a -> a) -> a -> MetaSet -> a
foldrMetaSet MetaId -> Set MetaId -> Set MetaId
forall a. Ord a => a -> Set a -> Set a
Set.insert Set MetaId
forall a. Set a
Set.empty) ([MetaSet] -> [Set MetaId]) -> [MetaSet] -> [Set MetaId]
forall a b. (a -> b) -> a -> b
$ IntMap MetaSet -> [MetaSet]
forall a. IntMap a -> [a]
IMap.elems IntMap MetaSet
flex
Blocker -> TCM ()
forall a. Blocker -> TCMT IO a
forall (m :: * -> *) a. MonadBlock m => Blocker -> m a
patternViolation (Blocker -> TCM ()) -> Blocker -> TCM ()
forall a b. (a -> b) -> a -> b
$ Set MetaId -> Blocker
unblockOnAnyMeta Set MetaId
metas
is <- (Int -> TCMT IO Bool) -> [Int] -> TCMT IO [Int]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM Int -> TCMT IO Bool
forall {f :: * -> *}. (MonadDebug f, MonadTCEnv f) => Int -> f Bool
isLock ([Int] -> TCMT IO [Int]) -> [Int] -> TCMT IO [Int]
forall a b. (a -> b) -> a -> b
$ VarSet -> [Int]
VarSet.toAscList (VarSet -> [Int]) -> VarSet -> [Int]
forall a b. (a -> b) -> a -> b
$ VarMap -> VarSet
rigidVars VarMap
fv
let mi | [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
Prelude.null [Int]
is = Maybe Int
forall a. Maybe a
Nothing
| Bool
otherwise = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Int]
is
pure mi
isTimeless :: Type -> TCM Bool
isTimeless :: Type'' Term Term -> TCMT IO Bool
isTimeless Type'' Term Term
t = do
t <- Type'' Term Term -> TCMT IO (Type'' Term Term)
forall (m :: * -> *) t.
(MonadReduce m, MonadBlock m, IsMeta t, Reduce t) =>
t -> m t
abortIfBlocked Type'' Term Term
t
timeless <- mapM getName' [builtinInterval, builtinIsOne]
case unEl t of
Def QName
q Elims
_ | QName -> Maybe QName
forall a. a -> Maybe a
Just QName
q Maybe QName -> [Maybe QName] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Maybe QName]
timeless -> Bool -> TCMT IO Bool
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
Term
_ -> Bool -> TCMT IO Bool
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
checkEarlierThan :: Term -> VarSet -> TCM Bool
checkEarlierThan :: Term -> VarSet -> TCMT IO Bool
checkEarlierThan Term
lk VarSet
fvs = do
Term -> TCMT IO (Maybe Int)
getLockVar Term
lk TCMT IO (Maybe Int) -> (Maybe Int -> TCMT IO Bool) -> TCMT IO Bool
forall a b. TCMT IO a -> (a -> TCMT IO b) -> TCMT IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe Int
Nothing -> Bool -> TCMT IO Bool
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
Just Int
i -> (Int -> TCMT IO Bool) -> [Int] -> TCMT IO Bool
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Monad m) =>
(a -> m Bool) -> f a -> m Bool
allM (Type'' Term Term -> TCMT IO Bool
isTimeless (Type'' Term Term -> TCMT IO Bool)
-> (Int -> TCMT IO (Type'' Term Term)) -> Int -> TCMT IO Bool
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Int -> TCMT IO (Type'' Term Term)
forall (m :: * -> *).
(MonadDebug m, MonadTCEnv m) =>
Int -> m (Type'' Term Term)
typeOfBV) ([Int] -> TCMT IO Bool) -> [Int] -> TCMT IO Bool
forall a b. (a -> b) -> a -> b
$ (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i) ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ VarSet -> [Int]
VarSet.toAscList VarSet
fvs